概要
本文主要是对.mp4进行解封装生成.264文件,使用ffplay进行播放。
/*指令提取 ffmpeg -i output.mp4 -an -vcodec copy -bsf: h264_mp4toannexb out.h264*/
整体架构流程
- 打开媒体文件(.mp4文件) avformat_open_input
- 获取码流信息 avformat_find_stream_info
- 获取视频流 av_find_best_stream
- 初始化packet(开始读取) av_init_packet
- 读取packet数据 av_read_frame
- 释放packet资源 av_packet_unref
- 关闭媒体文件 avformat_close_input
代码
const char* infilename = "/home/16THDD/xieyingbo/xieyingbo/big_buck_bunny.mp4";
const char* outfilename = "/home/16THDD/xieyingbo/xieyingbo/output.264";
//1.打开媒体文件(.mp4文件) avformat_open_input
av_register_all();
AVFormatContext *pFormatCtx = NULL;
int ret = avformat_open_input(&pFormatCtx, infilename, NULL, NULL);
if(ret != 0)
{
std::cout << "open input format error." << std::endl;
return;
}
//2.获取码流信息 avformat_find_stream_info
ret = avformat_find_stream_info(pFormatCtx, NULL);
if(ret < 0)
{
std::cout << "find stream error" << std::endl;
avformat_close_input(&pFormatCtx);
return;
}
//3.获取视频流 av_find_best_stream
int videoIndex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if(videoIndex < 0)
{
std::cout << "find best stream error" << std::endl;
avformat_close_input(&pFormatCtx);
return;
}
else
{
std::cout << "videoIndex = " << videoIndex << std::endl;
}
//4.初始化packet(开始读取)av_init_packet
AVPacket packet;
av_init_packet(&packet);
const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");
if(bsf == NULL)
{
std::cout << "h264_mp4 to annexb error" << std::endl;
avformat_close_input(&pFormatCtx);
return;
}
AVBSFContext *bsfCtx = NULL;
av_bsf_alloc(bsf, &bsfCtx);
avcodec_parameters_copy(bsfCtx->par_in, pFormatCtx->streams[videoIndex]->codecpar);
av_bsf_init(bsfCtx);
//5.读取packet数据 av_read_frame
FILE *ftp = fopen(outfilename, "wb");
if(ftp == NULL)
{
std::cout << "open infilename error" << std::endl;
avformat_close_input(&pFormatCtx);
return;
}
while(av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index == videoIndex)
{
if(av_bsf_send_packet(bsfCtx, &packet) == 0)
{
while(av_bsf_receive_packet(bsfCtx, &packet) == 0) //不一定一次就能接收完
{
if(fwrite(packet.data, 1, packet.size, ftp) != packet.size)
{
std::cout << "open infilename error" << std::endl;
fclose(ftp);
avformat_close_input(&pFormatCtx);
return;
}
}
}
}
//6.释放packet资源 av_packet_unref
av_packet_unref(&packet);
}
//7.关闭媒体文件 avformat_close_input
if(pFormatCtx)
{
avformat_close_input(&pFormatCtx);
}
if(ftp)
{
fclose(ftp);
}
if(bsfCtx)
{
av_bsf_free(&bsfCtx);
}
小结
/home/16THDD/xieyingbo/xieyingbo/emobile_2023-11-29_13-28-46.png