ffmpeg封装本公司的h264编码库

来源:互联网 发布:java else是什么意思 编辑:程序博客网 时间:2024/04/30 18:42

由于工作需要,要将本公司的h264编码库,封装到ffmpeg中,替换正式的x264编码库,

1、使用公司svn上的2.6.2的版本,总是libpostproc出错,后来想从官网上下载,但在http://ffmpeg.org/download.html是没有2.6.2的版本的,它是从2.5.11跳到2.6.9,

要在http://ffmpeg.org/releases/可以找到各种版本的原码。

2、ffmpeg中默认是没有x264的,要单独下载,可以从x264的官网上下载,也可以ffmpeg提供的链接上下载,同时https://trac.ffmpeg.org/有讲,ffmpeg和x264的编译的介绍,还有别的库,方法相同的,https://trac.ffmpeg.org/wiki/CompilationGuide/Quick/libx264

http://www.videolan.org/developers/x264.html可下载x264

3、编译x264

./configure --prefix=dstdir --enable-static --enable-shared

make clean && make && make install

4、由于公司的264编码有命名空间,直接放到ffmpeg中是不行的,写了一个包装库,也叫libx264.so

5、编译前,ffmpeg的configure会检查libx264.so的,如果没有会出错,所以运行configure时,x264的路径要能找到真正的libx264.so,

运行make && make install时,在将包装库替换正式的libx264.so

6、由于公司的编码库与正式的x264的函数名是相同的,不要将2个库同时链接。

7、编译ffmpeg前,修改ffmpeg的libavcodec/libx264.c,修改相应的X264_init,X264_frame,X264_close函数。

同时libx264中不能用bool, false,true,要用int要代替。

8、编码后pkt的时间戳,使用frme中的时间戳。

9、本来X264_init是要将到avctx->extradata的,但用自己的库要到X264_frame才能根据编码的流得到,

这就有个问题,如果这个数据不写,用vlc是可以看到视频,但用fms自带的播放器和平台播放器看不到视频,用flv分析工具可以看到第一个视频tag的数据只有5个字节。

然后用gdb查得分析的32字节的内容,写下固定的内容,用rtmp可以看到视频,但用hls,只能看到一种分辨率下的视频。

10、延时写头

10.1、 修改avformat.h的AVOutputFormat结构体,增加变量int n_need_late_write_head;//是否加延时写头, 0:不要,1:要

10.2、修改avcodec.h的AVCodecContext结构体,增加变量int n_need_late_write_head;//是否加延时写头, 0:不要,1:要

10.3、在X264_init中设置avctx->n_need_late_write_head = 1;

10.4、在avformat_write_header中增加

s->oformat->n_need_late_write_head = 0;
for(int i = 0; i < s->nb_streams; i++)
{
if(s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
if(s->streams[i]->codec->n_need_late_write_head == 1)
{
s->oformat->n_need_late_write_head = 1;
break;
}
}
}

if( 0 == s->oformat->n_need_late_write_head)//增加的控制变量
{。。。。写头}

10.5、在X264_frame调用

if(1 == g_need_AnalysisH264header)
{
if(AnalysisH264header(ctx, NULL, NULL, 0, g_pBufferOut, noutsize) != 0)
{
return -1;
}
}

分析出一次头就不要再分析了,就是得到extradata数据

10.6、write_frame中增加以下部分,就是写文件时,先写头(本来是前面要写的)

if(s->oformat != 0 && s->oformat->write_header && s->oformat->n_need_late_write_head == 1)
{
//一定要分析出头部才写头
if(ost->enc_ctx->extradata_size <= 10)//暂时写为10吧,正常是32
{
return;
}


for(int i = 0; i < s->nb_streams; i++)
{
if(s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
//将ost->enc_ctx的extradata 拷贝到s对应的流下
s->streams[i]->codec->extradata = malloc(ost->enc_ctx->extradata_size);
if(s->streams[i]->codec->extradata == 0)
{
av_log(NULL, AV_LOG_ERROR, "Failed malloc extradata\n");
return;
}
s->streams[i]->codec->extradata_size = ost->enc_ctx->extradata_size;
memcpy(s->streams[i]->codec->extradata, ost->enc_ctx->extradata, ost->enc_ctx->extradata_size);
}
}
//copy from avformat_write_header
int retw = s->oformat->write_header(s);
if (retw >= 0 && s->pb && s->pb->error < 0)
retw = s->pb->error;
if (retw < 0)
return retw;
if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);

s->oformat->n_need_late_write_head = 0;//下一次就不要写了
}

注意分配得到的数据在ost->enc_ctx中,要复制到s的视频流的codec中

0 0
原创粉丝点击