代码生成x264编码flv记录

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/smwhotjay/article/details/82428641

最近研究h264+aac 的flv直播 ,把flv格式完全的啃了下。下面简单说下。

flv 文件开始是9个字节的flv头。 46 4c 56 就是 F L V 的十六进制。第4个字节 01 表示FLV版本号

第5个字节表示文件音视频信息。1是只有视频, 5 音频和视频混合  4 只有音频。

再后面4个字节 0x00 0x00 0x00 0x09,转十进制为9,表示FLV header的长度.

然后后面4个字节是0 0 0 0 ,prev tag size 该值永远为0,因为文件才开始,一个tag都还没有呢。

然后后面就是tag了,通常都是第一个tag是脚本, 一个字节0x12 ,脚本里记录了flv一些必要的参数。比如视频音频编码,视频宽高

声音采样率,声道,文件大小,播放长度。tag结束后,会记录4个字节的prev tag size,标明上一个tag 的总长度

-------------------------------------------------------------------------------------------------------------------------------

声音tag 格式

tag head 11字节

11字节  =  TYPE 1字节  + Size 3字节 + timestamp 4字节 +streamID 3字节

TYPE 0x8表示音频tag

Size 为后面具体数据长度

streamID 永久为0

timestamp 时间戳

head后面接tag body

 

1个字节 定义了声音 编码 声道 采样率 。

如果这个声音是0x10  AAC编码,则后面有个1个AACPacketType 字节的数据。

然后后面就是声音实际数据了。

结束了就写入4字节的prev tag size, 一个tag就写入完毕。(注:aac 的编码还有个aac tag头 标明一些额外的aac信息,aac具体百度)

-----------------------------------------------------------------------------------------------------------------------------------

视频tag

tag head 11字节

11字节  =  TYPE 1字节  + Size 3字节 + timestamp 4字节 +streamID 3字节

TYPE 0x9表示视频tag

Size 为后面具体数据长度

streamID 永久为0

timestamp 时间戳

head后面接tag body

-------------------------------------------------------------

由于x264编码,我们flv文件必须在实际视频tag之前把pps sps相关参数标明,不然后续解码器无法工作。

即flv头+prevtagsize+ 0x12的脚本tag + 0x9视频tag头(11字节)+ 0x17 0x00 0x00 0x00 0x00 0x01 sps[1]  sps[2] sps[3]  0xff  0xe1 ....0x9视频tag整体包长4字节+ xTag+xBody+PrevTagSize+.....

最先开始的0x9视频tag 即装的是sps pps数据。然后后续的视频tag才装实际的nalu数据。

数据包格式 

0x9视频tag头(11字节)+ frametype&codecID 1字节+ 0x01(avcPacketType)+ 0x00 0x00 0x00 (composition3字节,具体值要看avcPacketType)+  4字节记录后面NALU数据的长度 +  具体NALU数据+ prev tag size.  

 

 

 

 

 

展开阅读全文

x264帧编码延迟

11-05

研究了一下x264编码延时.rn方法是加log在x264.crnstatic int encode( x264_param_t *param, cli_opt_t *opt )rnrn ...rn i_frame_size = encode_frame( h, opt->hout, &pic, &last_dts );rn if( i_frame_size == 0) // delay framesrn fprintf( stderr, "output zero %d\n", i_frame );rn ...rnrnrn统计了一下,发现x264编码延时帧数符合下面的公式。rn h->frames.i_delay =rn param->i_sync_lookahead + // 前向考虑帧数rn max ( param->i_bframe, // B帧数量rn param->rc.i_lookahead) + // 码率控制前向考虑帧数rn param->i_threads - 1. // 并行编码帧数rnrn延迟有两种:rn1.编码前延时(当前帧没有编码,需要buffer更多帧后才能开始编码)。rn 这种延时出口在 encoder.c, x264_encoder_encode函数rn ...rn if( h->frames.i_input <= h->frames.i_delay + 1 - h->i_thread_frames )rn rn /* Nothing yet to encode, waiting for filling of buffers */rn pic_out->i_type = X264_TYPE_AUTO;rn return 0;rn rn ...rn i_sync_lookahead, i_bframe, rc.i_lookahead 都会在此影响延时。rnrn2. 编码后延时(当前帧已经编码,但后续帧还没编码,只好先退出)。rn 这种延时出口在 encoder.c, x264_encoder_frame_end函数rn if( !h->out.i_nal )rn rn pic_out->i_type = X264_TYPE_AUTO;rn return 0;rn rn 这部分延时是因为x264并行帧编码引起的。rn x264并行帧编码每一次都是把一个帧组(i_threads个并行处理帧)处理完后,再处理下一个帧组。rnrn根据公式看到减少帧延时的方法,也就是(zerolatency 设置)rn param->rc.i_lookahead = 0;rn param->i_sync_lookahead = 0;rn param->i_bframe = 0;rn param->b_sliced_threads = 1; rn param->b_vfr_input = 0;rn param->rc.b_mb_tree = 0;rnrn这个设置h->frames.i_delay = 0。但其中param->b_sliced_threads = 1 的设置值得怀疑。rn当b_sliced_threads = 1时,x264放弃帧并行编码,这必然会影响编码速度。rn一个折中的办法是设置b_sliced_threads = 0,其他按照zerolatency 设置。rn这样h->frames.i_delay = param->i_threads - 1。rnx264根据CPU自动计算i_threads,一般为6/8. 这样的帧群延迟大概是1/3-1/2秒。rn看具体系统的需要能否满足。rnrn这样看x264并行帧编码写的还不是很自适应。rn如果能够让i_threads在编码起始阶段随着输入帧数的增加而增加,那样就可以彻底解决编码群延时的问题了。rn个人想法,未经验证,欢迎指正。 论坛

x264编码后图像是灰色的

04-26

用yuv420图像输入,我用opencv的BGR和其他格式的RGB色彩都没问题。但就是yuv420编码结果是黑白的,我把yuv420图像单独输出,显示的也是正常的。图像不是很了解,请帮我看下,是不是哪地方搞错了,我怀疑的地方已标出。rn[code=c]rnrnint ret;rn int y_size;rn int i, j;rn VideoCapture cam(0);rn FILE* fp_dst = fopen("d:\\x264.h264", "wb");rn FILE* pFileOut = fopen("d:\\X264.yuv", "w+");rn int frame_num = 0;rn int csp = X264_CSP_I420;rn int width = 640, height = 480;rnrn int iNal = 0;rn x264_nal_t* pNals = NULL;rn x264_t* pHandle = NULL;rn x264_picture_t* pPic_in = (x264_picture_t*)malloc(sizeof(x264_picture_t));rn x264_picture_t* pPic_out = (x264_picture_t*)malloc(sizeof(x264_picture_t));rn x264_param_t* pParam = (x264_param_t*)malloc(sizeof(x264_param_t));rnrn x264_param_default(pParam);rn pParam->i_width = width;rn pParam->i_height = height;rnrn pParam->i_csp = csp;rn x264_param_apply_profile(pParam, x264_profile_names[5]);rnrn pHandle = x264_encoder_open(pParam);rnrn x264_picture_init(pPic_out);rn x264_picture_alloc(pPic_in, csp, pParam->i_width, pParam->i_height);rnrn y_size = pParam->i_width * pParam->i_height;rn //Loop to Encodern for (i = 0; i <= 200; i++)rn Mat edges;rn cam >> edges;rn Mat yuv;rn cv::cvtColor(edges, yuv, COLOR_BGR2YUV_I420);rn rn //怀疑这里出问题了rn memcpy(pPic_in->img.plane[0], yuv.data, y_size);rn memcpy(pPic_in->img.plane[1], yuv.data, y_size/4);rn memcpy(pPic_in->img.plane[2], yuv.data, y_size/4);rnrn fwrite(yuv.data, pParam->i_width * pParam->i_height * 3 / 2, 1, pFileOut);rnrn pPic_in->i_pts = i;rnrn ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);rn if (ret< 0)rn printf("Error.\n");rn return -1;rn rnrn printf("Succeed encode frame: %5d\n", i);rn rn for (j = 0; j < iNal; ++j)rn fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);rn rn waitKey(30);rn rnrn x264_picture_clean(pPic_in);rn x264_encoder_close(pHandle);rn pHandle = NULL;rnrn free(pPic_in);rn free(pPic_out);rn free(pParam);rn fclose(pFileOut);rn fclose(fp_dst);rnrn[/code] 论坛

没有更多推荐了,返回首页