FFmpeg4.0笔记:本地媒体文件解码
程序员文章站
2022-04-28 15:42:45
Github https://github.com/gongluck/FFmpeg4.0 study/blob/master/official%20example/my_example.cpp C++ include include // define NOVIDEO // define NOAUD ......
github
https://github.com/gongluck/ffmpeg4.0-study/blob/master/official%20example/my_example.cpp
#include <iostream> #include <fstream> //#define novideo //#define noaudio #ifdef __cplusplus extern "c" { #endif // ffmpeg 头文件 #include "libavformat/avformat.h" #ifdef __cplusplus } // c++中使用av_err2str宏 char av_error[av_error_max_string_size] = { 0 }; #define av_err2str(errnum) \ av_make_error_string(av_error, av_error_max_string_size, errnum) #endif int main(int argc, char* argv[]) { avformatcontext* fmt_ctx = nullptr; avcodeccontext *vcodectx = nullptr, *acodectx = nullptr; avcodecparameters *vcodecpar = nullptr, *acodecpar = nullptr; avcodec *vcodec = nullptr, *acodec = nullptr; avpacket* pkt = nullptr; avframe* frame = nullptr; std::ofstream out_yuv, out_pcm; const char* in = "in.flv"; int vindex = -1, aindex = -1; int ret = 0; out_yuv.open("out.yuv", std::ios::binary | std::ios::trunc); out_pcm.open("out.pcm", std::ios::binary | std::ios::trunc); if (!out_yuv.is_open() || !out_pcm.is_open()) { std::cerr << "创建/打开输出文件失败" << std::endl; goto end; } // 日志 av_log_set_level(av_log_error); // 打开输入 ret = avformat_open_input(&fmt_ctx, in, nullptr, nullptr); if (ret < 0) { std::cerr << "avformat_open_input err : " << av_err2str(ret) << std::endl; goto end; } // 查找流信息,对输入进行预处理 ret = avformat_find_stream_info(fmt_ctx, nullptr); if (ret < 0) { std::cerr << "avformat_find_stream_info err : " << av_err2str(ret) << std::endl; goto end; } // 打印输入信息 av_dump_format(fmt_ctx, 0, fmt_ctx->url, 0); //查找流 for (int i = 0; i < fmt_ctx->nb_streams; ++i) { if (fmt_ctx->streams[i]->codecpar->codec_type == avmedia_type_video) { vindex = i; } else if (fmt_ctx->streams[i]->codecpar->codec_type == avmedia_type_audio) { aindex = i; } } if (vindex == -1) { std::cerr << "找不到视频流" << std::endl; } if (aindex == -1) { std::cerr << "找不到音频流" << std::endl; } //查找解码器 vcodecpar = fmt_ctx->streams[vindex]->codecpar; vcodec = avcodec_find_decoder(vcodecpar->codec_id); if (vcodec == nullptr) { std::cerr << "avcodec_find_decoder err : " << av_err2str(ret) << std::endl; goto end; } acodecpar = fmt_ctx->streams[aindex]->codecpar; acodec = avcodec_find_decoder(acodecpar->codec_id); if (acodec == nullptr) { std::cerr << "avcodec_find_decoder err : " << av_err2str(ret) << std::endl; goto end; } //打开解码器 vcodectx = avcodec_alloc_context3(vcodec); ret = avcodec_parameters_to_context(vcodectx, vcodecpar);// 参数拷贝 if (ret < 0) { std::cerr << "avcodec_parameters_to_context err : " << av_err2str(ret) << std::endl; goto end; } ret = avcodec_open2(vcodectx, vcodec, nullptr); if (ret < 0) { std::cerr << "avcodec_open2 err : " << av_err2str(ret) << std::endl; goto end; } acodectx = avcodec_alloc_context3(acodec); ret = avcodec_parameters_to_context(acodectx, acodecpar);// 参数拷贝 if (ret < 0) { std::cerr << "avcodec_parameters_to_context err : " << av_err2str(ret) << std::endl; goto end; } ret = avcodec_open2(acodectx, acodec, nullptr); if (ret < 0) { std::cerr << "avcodec_open2 err : " << av_err2str(ret) << std::endl; goto end; } // 创建avpacket pkt = av_packet_alloc(); if (pkt == nullptr) { std::cerr << "av_packet_alloc err : " << std::endl; goto end; } av_init_packet(pkt); // 创建avframe frame = av_frame_alloc(); if (frame == nullptr) { std::cerr << "av_frame_alloc err : " << std::endl; goto end; } // 从输入读取数据 while (av_read_frame(fmt_ctx, pkt) >= 0) { if (pkt->stream_index == vindex) { #ifndef novideo // 解码视频帧 ret = avcodec_send_packet(vcodectx, pkt); if (ret < 0) { std::cerr << "avcodec_send_packet err : " << av_err2str(ret) << std::endl; break; } while (ret >= 0) { ret = avcodec_receive_frame(vcodectx, frame); if (ret == averror(eagain) || ret == averror_eof) { break; } else if (ret < 0) { std::cerr << "avcodec_receive_frame err : " << av_err2str(ret) << std::endl; break; } else { // 得到解码数据 if (frame->format == av_pix_fmt_yuv420p) { out_yuv.write(reinterpret_cast<const char*>(frame->data[0]), frame->linesize[0] * frame->height); out_yuv.write(reinterpret_cast<const char*>(frame->data[1]), frame->linesize[1] * frame->height / 2); out_yuv.write(reinterpret_cast<const char*>(frame->data[2]), frame->linesize[2] * frame->height / 2); } } } #endif // novideo } else if (pkt->stream_index == aindex) { #ifndef noaudio // 解码音频帧 ret = avcodec_send_packet(acodectx, pkt); if (ret < 0) { std::cerr << "avcodec_send_packet err : " << av_err2str(ret) << std::endl; break; } while (ret >= 0) { ret = avcodec_receive_frame(acodectx, frame); if (ret == averror(eagain) || ret == averror_eof) { break; } else if (ret < 0) { std::cerr << "avcodec_receive_frame err : " << av_err2str(ret) << std::endl; break; } else { // 得到解码数据 if (frame->format == av_sample_fmt_fltp) { /// 参考了https://www.cnblogs.com/my_life/articles/6841859.html // 计算一个planar的有效大小,很关键! auto size = av_get_bytes_per_sample(static_cast<avsampleformat>(frame->format)) * frame->nb_samples; for (int i = 0; i < size; i += 4) { for (int j = 0; j < frame->channels; ++j) { out_pcm.write(reinterpret_cast<const char*>(frame->data[j] + i), 4); } } } } } #endif // noaudio } // 复位data和size av_packet_unref(pkt); } end: std::cerr << "end..." << std::endl; std::cin.get(); out_yuv.close(); out_pcm.close(); av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&vcodectx); avcodec_free_context(&acodectx); avformat_close_input(&fmt_ctx); return 0; }
上一篇: Django学习之十三:提高页面开发效率减少冗余的模板系统
下一篇: qt学习笔记