系列索引:FFmpeg入门系列索引
上一篇:FFmpeg入门教程10.11:本地yuv文件编码为h264
上一篇将yuv源视频文件编码为*.h264
的由libx264实现压缩的文件,将源文件从55M编码为620KB,但是h264文件只有视频数据,而且使用范围不太广。那么就需要进一步的封装,在此选用最常用的mp4格式为例。
随便选一个mp4格式文件,用FFmpeg入门教程04:解析视频并输出视频信息 或者ffprobe查看一下数据。
迈克尔杰克逊的beat it.mp4
,输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 Input Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf57.73.100 Duration: 00:05:00.88, start: 0.000000, bitrate: 683 kb/s Stream Metadata: handler_name : VideoHandler Stream Metadata: handler_name : SoundHandler
有两条流,一条h264的视频流,一条aac的音频流。现在我们有h264的流,创建一个mp4文件,新建一条流并将h264流插入进去。(暂时没有音频部分)
转换流程图为:
flowchart TB
E --Yes--> P[时间戳转换]
P --> O
O --读取下一帧--> E
subgraph output
direction TB
G(输出) --> H[分配输出格式上下文]
H --> I[打开输出文件]
I --> J[创建视频流]
J --> K[查找编码器]
K --> L[设置编码器参数]
L --> M[打开编码器]
M --> O[写入文件]
end
subgraph input
direction TB
A(输入) --> B[打开输入文件]
B --> C[查找信息流]
C --> D[查找视频流索引]
D --> E{读取帧}
E --No--> F(释放资源)
end
h264->mp4 打开输入文件(h264)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 if (avformat_open_input (&inVFmtCtx,inVFileName,NULL ,NULL )<0 ){ printf ("Cannot open input file.\n" ); break ; }if (avformat_find_stream_info (inVFmtCtx,NULL )<0 ){ printf ("Cannot find stream info in input file.\n" ); break ; }for (size_t i=0 ;i<inVFmtCtx->nb_streams;i++){ if (inVFmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){ inVStreamIndex=(int )i; break ; } } AVCodecParameters *codecPara = inVFmtCtx->streams[inVStreamIndex]->codecpar;printf ("===============Input information========>\n" );av_dump_format (inVFmtCtx, 0 , inVFileName, 0 );printf ("===============Input information========<\n" );
可以看到和正常打开视频文件一样,或者说除了原始视频文件(yuv格式)其他格式打开代码差不多。
打开输出文件(mp4)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 if (avformat_alloc_output_context2 (&outFmtCtx,NULL ,NULL ,outFileName)<0 ){ printf ("Cannot alloc output file context.\n" ); break ; }if (avio_open (&outFmtCtx->pb,outFileName,AVIO_FLAG_READ_WRITE)<0 ){ printf ("output file open failed.\n" ); break ; } AVStream *outVStream = avformat_new_stream (outFmtCtx,NULL );if (!outVStream){ printf ("Failed allocating output stream.\n" ); break ; } outVStream->time_base.den=25 ; outVStream->time_base.num=1 ; outVStreamIndex=outVStream->index; AVCodec *outCodec = avcodec_find_encoder (codecPara->codec_id);if (outCodec==NULL ){ printf ("Cannot find any encoder.\n" ); break ; } AVCodecContext *outCodecCtx=avcodec_alloc_context3 (outCodec); AVCodecParameters *outCodecPara = outFmtCtx->streams[outVStream->index]->codecpar;if (avcodec_parameters_copy (outCodecPara,codecPara)<0 ){ printf ("Cannot copy codec para.\n" ); break ; }if (avcodec_parameters_to_context (outCodecCtx,outCodecPara)<0 ){ printf ("Cannot alloc codec ctx from para.\n" ); break ; } outCodecCtx->time_base.den=25 ; outCodecCtx->time_base.num=1 ;if (avcodec_open2 (outCodecCtx,outCodec,NULL )<0 ){ printf ("Cannot open output codec.\n" ); break ; }printf ("============Output Information=============>\n" );av_dump_format (outFmtCtx,0 ,outFileName,1 );printf ("============Output Information=============<\n" );
和上一篇类似。
编码部分源文件是h264,MP4中的流也是h264,也就是说实际上并没有真正意义上的编码过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 if (avformat_write_header (outFmtCtx,NULL )<0 ){ printf ("Cannot write header to file.\n" ); return -1 ; } AVStream *inVStream = inVFmtCtx->streams[inVStreamIndex];while (av_read_frame (inVFmtCtx,pkt)>=0 ){ if (pkt->stream_index==inVStreamIndex){ if (pkt->pts==AV_NOPTS_VALUE){ printf ("frame_index:%d\n" , frame_index); AVRational time_base1 = inVStream->time_base; int64_t calc_duration = (double )AV_TIME_BASE / av_q2d (inVStream->r_frame_rate); pkt->pts = (double )(frame_index*calc_duration) / (double )(av_q2d (time_base1)*AV_TIME_BASE); pkt->dts = pkt->pts; pkt->duration = (double )calc_duration / (double )(av_q2d (time_base1)*AV_TIME_BASE); frame_index++; } pkt->pts = av_rescale_q_rnd (pkt->pts, inVStream->time_base, outVStream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); pkt->dts = av_rescale_q_rnd (pkt->dts, inVStream->time_base, outVStream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); pkt->duration = av_rescale_q (pkt->duration, inVStream->time_base, outVStream->time_base); pkt->pos = -1 ; pkt->stream_index = outVStreamIndex; printf ("Write 1 Packet. size:%5d\tpts:%ld\n" , pkt->size, pkt->pts); if (av_interleaved_write_frame (outFmtCtx, pkt) < 0 ) { printf ("Error muxing packet\n" ); break ; } av_packet_unref (pkt); } }av_write_trailer (outFmtCtx);
只是一些时间戳方面的处理。
软件输出1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ===============Input information========> Input Duration: N/A, bitrate: N/A Stream ===============Input information========< Cannot open libmwv206dec.so, libmwv206dec.so: cannot open shared object file: No such file or directory [libx264 @ 0x162cd00] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 [libx264 @ 0x162cd00] profile High, level 1.3 ============Output Information=============> Output Stream ============Output Information=============< OutVIndex=0,pkt.stream_index=0 frame_index==0 Write 1 Packet. size: 6899 pts:0 ...共300个
Cannot open libmwv206dec.so ...
是deepin linux系统错误。
执行完毕后得到只有视频没有音频的mp4文件。
完整代码在ffmpeg_beginner 中10.12.video_encode_h2642mp4
里面。
下一篇:FFmpeg入门教程10.13:Linux下摄像头捕获并编码为h264(无音频)