Mp4v2实现h264+aac打包成Mp4视频文件

原出处 http://blog.csdn.net/jwzhangjie/article/details/8857892  

  使用mp4v2实现录制mp4视频,需要准备如下信息:

1、获取mp4v2源码并编译成库文件,对于mp4v2的编译可以看前面的文章android 编译mp4v2 2.0.0生成动态库

2、获取h264数据中的sps和pps数据,如果不会的话可以查看前面的文章 点击打开链接

3、获取音频解码信息,在调用MP4SetTrackESConfiguration使用,具体的获取方式一种通过faac获取,方法faacEncGetDecoderSpecificInfo(hEncoder,&(ASC), &(ASCLength));//得到解码信息另一种查看aac音频源码,并并对照aac的adts头格式分析: 

前五个字节为 AAC object types  LOW     2  
接着4个字节为 码率index        16000      8  
接着4个字节为 channels 个数                 1  
应打印出的正确2进制形式为  00010 | 1000 | 0001 | 000  
                                                            2          8        1

所以为(20,8)

4、规定时间刻度问题,一般网上都是设置90000,这个90000是指1秒的tick数,其实也就是把1秒中分为90000份,在添加音视频的函数中

durationMP4_INVALID_DURATION

 

bool MP4WriteSample(  
MP4FileHandle hFile,  
  
MP4TrackId trackId,  
  
u_int8_t* pBytes,  
  
u_int32_t numBytes,  
  
MP4Duration duration = MP4_INVALID_DURATION,  
  
MP4Duration renderingOffset = 0,  
  
bool isSyncSample = true   //如果是视频,此处是指当前视频帧是否是关键帧,如果是则为1,如果不是则为0   
  
); 
其中duration这个参数是指视频帧存在的时间,在90000这个刻度上存在的时间,如果用户确定录像时的音频视频帧是按固定速率的,那么在这里可以设置MP4_INVALID_DURATION,这时mp4v2就会使用下面的函数中的时间刻度

视频: 

MP4AddH264VideoTrack(MP4FileHandle hFile,  
                                    uint32_t timeScale,  
                                    MP4Duration sampleDuration,  
                                    uint16_t width,  
                                    uint16_t height,  
                                    uint8_t AVCProfileIndication,  
                                    uint8_t profile_compat,  
                                    uint8_t AVCLevelIndication,  
                                    uint8_t sampleLenFieldSizeMinusOne)  
sampleDuration为视频的固定的视频帧的显示时间,计算的方法为timeScale(90000)* during(这个值是当前视频帧的采集时间 - 上一帧的视频  
采集时间)/1000,公式也可以改为timeScale(90000)/fps(码率例如20f) 
音频:  
MP4TrackId MP4AddAudioTrack(  
MP4FileHandle hFile,  
  
u_int32_t timeScale,  
  
u_int32_t sampleDuration,  
  
u_int8_t audioType = MP4_MPEG4_AUDIO_TYPE  
  
)   
sampleDuration 是音频的音频帧在时间刻度上存在的时间,这里的timeScale为音频的采样时间,例如44100,32000,计算方法给上面的视频一样的。  
sampleDuration主要作用是用于音视频同步问题 
5、mp4v2录制视频中h264的格式要求:长度+NAL数据,如果传过来的数据没有 则是纯数据    
(1)h264流中的NAL,头四个字节是0x00000001; 
(2)mp4中的h264track,头四个字节要求是NAL的长度,并且是大端顺序;  
(3)mp4v2很可能针对此种情况并没有做处理,所以写到mp4文件中的每个NAL头四个字节还是0x00000001.  
因此如果传过来的h264数据是纯数据的话则需要如下修改: 
      int nalsize = frameSize;  
      buf[0] = (nalsize&0xff000000)>>24;  
      buf[1] = (nalsize&0x00ff0000)>>16;  
      buf[2] = (nalsize&0x0000ff00)>>8;  
      buf[3] = nalsize&0x000000ff;
如果头部格式有其他的,则按照上面的方式偏移到纯数据位置。 
6、mp4v2录制视频中aac的格式要求:有时远程传过来的aac数据的格式为adts+aac纯数据,则需要将adts部分去掉,即需要偏移7个字节的单位  
下面就开始编写如何调用mp4v2库的方法:  
#include <stdio.h>  
#include <string.h>   
#include "../mp4v2/mp4v2.h"   
#include "AppCameraShooting.h"   
  
MP4TrackId video;  
MP4TrackId audio;  
MP4FileHandle fileHandle;  
unsigned char sps_pps_640[17] = {0x67, 0x42, 0x40, 0x1F, 0x96 ,0x54, 0x05, 0x01, 0xED, 0x00, 0xF3, 0x9E, 0xA0, 0x68, 0xCE, 0x38, 0x80}; //存储sps和pps   
int video_width = 640;  
int video_height = 480;  
  
//视频录制的调用,实现初始化   
    JNIEXPORT bool JNICALL Java_com_seuic_jni_AppCameraShooting_mp4init  
(JNIEnv *env, jclass clz, jstring title, jint type)  
{  
    const char* local_title = (*env)->GetStringUTFChars(env,title, NULL);  
    //创建mp4文件   
    fileHandle = MP4Create(local_title, 0);  
    if(fileHandle == MP4_INVALID_FILE_HANDLE)  
    {  
        return false;  
    }  
    memcpy(sps_pps, sps_pps_640, 17);  
    video_width = 640;  
    video_height = 480;  
    //设置mp4文件的时间单位   
    MP4SetTimeScale(fileHandle, 90000);  
    //创建视频track //根据ISO/IEC 14496-10 可知sps的第二个,第三个,第四个字节分别是 AVCProfileIndication,profile_compat,AVCLevelIndication     其中90000/20  中的20>是fps   
    video = MP4AddH264VideoTrack(fileHandle, 90000, 90000/20, video_width, video_height, sps_pps[1], sps_pps[2], sps_pps[3], 3);  
    if(video == MP4_INVALID_TRACK_ID)  
    {  
        MP4Close(fileHandle, 0);  
        return false;  
    }  
    audio = MP4AddAudioTrack(fileHandle, 16000, 1024, MP4_MPEG2_AAC_LC_AUDIO_TYPE);  
    if(audio == MP4_INVALID_TRACK_ID)  
    {  
        MP4Close(fileHandle, 0);  
        return false;  
  
    }  
    //设置sps和pps   
    MP4AddH264SequenceParameterSet(fileHandle, video, sps_pps, 13);  
    MP4AddH264PictureParameterSet(fileHandle, video, sps_pps+13, 4);  
    MP4SetVideoProfileLevel(fileHandle, 0x7F);  
    MP4SetAudioProfileLevel(fileHandle, 0x02);  
    MP4SetTrackESConfiguration(fileHandle, audio, &ubuffer[0], 2);  
    (*env)->ReleaseStringUTFChars(env, title, local_title);  
    return true;  
}  
    //添加视频帧的方法   
    JNIEXPORT void JNICALL Java_com_seuic_jni_AppCameraShooting_mp4packVideo  
(JNIEnv *env, jclass clz, jbyteArray data, jint size, jint keyframe)  
{  
    unsigned char *buf = (unsigned char *)(*env)->GetByteArrayElements(env, data, JNI_FALSE);  
    if(video_type == 1){  
        int nalsize = size;  
        buf[0] = (nalsize & 0xff000000) >> 24;  
        buf[1] = (nalsize & 0x00ff0000) >> 16;  
        buf[2] = (nalsize & 0x0000ff00) >> 8;  
        buf[3] =  nalsize & 0x000000ff;  
        MP4WriteSample(fileHandle, video, buf, size, MP4_INVALID_DURATION, 0, keyframe);  
    }  
    (*env)->ReleaseByteArrayElements(env, data, (jbyte *)buf, 0);  
}  
  
    //添加音频帧的方法   
    JNIEXPORT void JNICALL Java_com_seuic_jni_AppCameraShooting_mp4packAudio  
(JNIEnv *env, jclass clz, jbyteArray data, jint size)  
{  
    uint8_t *bufaudio = (uint8_t *)(*env)->GetByteArrayElements(env, data, JNI_FALSE);  
    MP4WriteSample(fileHandle, audio, &bufaudio[7], size-7, MP4_INVALID_DURATION, 0, 1); //减去7为了删除adts头部的7个字节   
    (*env)->ReleaseByteArrayElements(env, data, (jbyte *)bufaudio, 0);  
}  
  
    //视频录制结束调用   
    JNIEXPORT void JNICALL Java_com_seuic_jni_AppCameraShooting_mp4close  
(JNIEnv *env, jclass clz)  
{  
    MP4Close(fileHandle, 0);  
} 

谢谢这位兄弟了。对我帮助很大。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
使用 MP4v2 AAC 编码音频写 M4A 文件可以通过以下步骤完: 首先,需要准备好要写入的音频数据,并使用 AAC 编码格式进行编码。AAC 是一种广泛使用的音频编码格式,可以提供高质量的音频压缩。可以使用 MP4v2 库中的编码器功能将音频数据转换为 AAC 格式。 接下来,在使用 MP4v2 库之前,需要确保已经正确安装和配置了该库。根据操作系统的不同,可以在官方网站上找到相关的安装和配置指南。 一旦确认库的安装和配置完毕,就可以开始编写代码了。首先,需要导入 MP4v2 库,并创建一个 MP4 文件对象。然后,通过调用 MP4SetAudioProfileLevel 函数设置音频的编码参数,例如比特率、声道数等。 接下来,需要将编码后的 AAC 音频数据写入 M4A 文件。可以使用 MP4WriteSample 函数来实现这一步骤。需要注意的是,写入音频数据时需要指定音频帧的时间戳,以确保音频数据的顺序正确。 最后,需要调用 MP4Close 函数来关闭文件,保存并释放资源。 使用 MP4v2 AAC 编码音频写 M4A 文件的示例代码如下: ```cpp #include <mp4v2/mp4v2.h> void writeM4AFile(const char* audioFileName, const char* outputFile) { MP4FileHandle fileHandle = MP4Create(outputFile); // 设置音频编码参数 MP4SetAudioProfileLevel(fileHandle, 0x2); // AAC-LC MP4SetAudioChannels(fileHandle, 2); // 声道数 MP4SetAudioDuration(fileHandle, 0); // 设置音频时长(可选) MP4SetAudioProfileLevel(fileHandle, 0x15); // 采样率 // 打开音频文件 FILE* audioFile = fopen(audioFileName, "rb"); if (audioFile != NULL) { // 读取音频数据并写入 M4A 文件 while (!feof(audioFile)) { unsigned char buffer[1024]; size_t bytesRead = fread(buffer, 1, sizeof(buffer), audioFile); MP4WriteSample(fileHandle, 1, buffer, bytesRead, MP4_INVALID_DURATION, 0, 1); } fclose(audioFile); } // 关闭文件,保存并释放资源 MP4Close(fileHandle, MP4_CLOSE_DO_NOT_COMPUTE); } int main() { const char* audioFileName = "audio.pcm"; const char* outputFile = "output.m4a"; writeM4AFile(audioFileName, outputFile); return 0; } ``` 上述代码是一个简单的示例,需要根据具体的需求进行适当的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值