概述
【FFmpeg编程实战】(2)分离视频文件中的视频流每一张图片(进阶)(C)
- 一、代码修改
- 二、运行结果
- 三、完整代码
在前文《【FFmpeg解码实战】(1)分离视频文件中的音频流和视频流》中,
我们实现了对视频的解复用功能,以MP4为例,解复用后为 H264视频流 和 AAC音频流。
本文在前文的基础上,来实现将前面的代码修改为不保存H264
文件,而是保存成一张一张的yuv420p
图片。
本文VS2019项目工程所有文件已打包上传到CSDN,欢迎下载:《VS2019-解码视频-工程所有文件.zip》,
注意工程中需要配置ffmpeg 的lib库路径及头文件路径才可使用本文链接:《【FFmpeg解码实战】(2)分离视频文件中的视频流每一张图片(进阶)(C)》
一、代码修改
其实很简闲单,修改的地方也不多,如下:
在保存 h264 video 视频流时,分开来,保存成 video/Video_Test_out.yuv420p.0.yuv
,
图片名字,根据 video_frame_count++
的自加而变化。
#define YUV420P_FILE 1 // 视频流保存成 yuv420p 图片
//#define H264_FILE 1 // 视频流保存成 H264 文件
#ifdef H264_FILE
sprintf_s(video_dst_filename, 50, "%s.%s", "Video_Test_out", video_dec->name);
ret = fopen_s(&video_dst_file, video_dst_filename, "wb");
printf("open file:%s ret:%dn", video_dst_filename, ret);
#endif
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
// 10. 视频数据解码
if (pkt.stream_index == video_stream_idx)
{
......
#ifdef YUV420P_FILE
// 10.4 写入文件
sprintf_s(video_dst_filename, 50, "video/%s.%s.%d.yuv", "Video_Test_out",
av_get_pix_fmt_name(video_dec_ctx->pix_fmt), video_frame_count++);
ret = fopen_s(&video_dst_file, video_dst_filename, "wb");
//printf("open file:%s ret:%dn", video_dst_filename, ret);
#endif
ret = (int)fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);
//printf("Write Size:%dn", ret);
#ifdef YUV420P_FILE
fclose(video_dst_file);
#endif
}
......
}
......
#ifdef H264_FILE
fclose(video_dst_file);
#endif
二、运行结果
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Video_Test.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
Duration: 00:02:45.92, start: 0.000000, bitrate: 1076 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 975 kb/s, 24.98 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (HE-AAC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 96 kb/s (default)
Metadata:
handler_name : SoundHandler
#===> Find video_stream_idx = 0
#===> Find decoder: h264, coded_id:27 long name: H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 pix_fmt=0 (yuv420p)
#===> Find audio_stream_idx = 1
#===> Find decoder: aac, coded_id:86018 long name: AAC (Advanced Audio Coding)
open file:Video_Test_out.aac ret:0
Start read frame
Demuxing succeeded.
Play the output video file with the command:
ffplay -f rawvideo -pix_fmt yuv420p -video_size 1280x720 video/Video_Test_out.yuv420p.4139.yuv
Warning: the sample format the decoder produced is planar (fltp). This example will output the first channel only.
Play the output audio file with the command:
ffplay -f f32le -ac 1 -ar 44100 Video_Test_out.aac
查看yuv图片, ffplay -f rawvideo -pix_fmt yuv420p -video_size 1280x720 Video_Test_out.yuv420p.1000.yuv
三、完整代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/timestamp.h> //av_ts2timestr
#include <libavutil/samplefmt.h>
#define YUV420P_FILE 1 // 视频流保存成 yuv420p 图片
//#define H264_FILE 1 // 视频流保存成 H264 文件
static int get_format_from_sample_fmt(const char** fmt, enum AVSampleFormat sample_fmt)
{
int i;
struct sample_fmt_entry {
enum AVSampleFormat sample_fmt; const char* fmt_be, * fmt_le;
} sample_fmt_entries[] = {
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
};
*fmt = NULL;
for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
struct sample_fmt_entry* entry = &sample_fmt_entries[i];
if (sample_fmt == entry->sample_fmt) {
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
return 0;
}
}
fprintf(stderr,"sample format %s is not supported as output formatn", av_get_sample_fmt_name(sample_fmt));
return -1;
}
// 参考:ffplay.c、demuxing_decoding.c
int main(int argc, char* argv[])
{
int ret = 0;
//printf("%s n",avcodec_configuration());
// 定义文件名
unsigned char input_filename[] = "video.mp4";
unsigned char out_filename[] = "video_out";
unsigned char video_dst_filename[50]; // = "Video_Test_out.h264";
unsigned char audio_dst_filename[50]; // = "Video_Test_out.aac";
memset(video_dst_filename, '