ffmpeg转码transcode,不依赖filter
作者:互联网
此代码可以把视频编码方式为H264,音频编码方式为AAC的FLV转换成视频编码方式为mpg1video,音频编码方式为AAC的MP4。此程序资源释放可能有问题
包括了视频的解复用,复用,转码,时间戳转换
ffmpeg版本4.3
static int nVideoStream_idx_in = -1;//输入文件的视频流编号
static int nAudioStream_idx_in = -1;//输入文件的音频流编号
static void openVidoEncoder_mpg1video(int width, int height,AVFormatContext *ofmt_ctx,AVCodecContext** enc_ctx)
{
int nRet = 0;
AVStream *stream = nullptr;
AVCodec *codec_mpeg1 = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);
if(!codec_mpeg1)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
if (!(stream = avformat_new_stream(ofmt_ctx, codec_mpeg1)))
{
fprintf(stderr, "Could not allocate video codec context\n");
return;
}
(*enc_ctx) = avcodec_alloc_context3(codec_mpeg1);
if ((* enc_ctx) == nullptr)
{
fprintf(stderr, "Could not allocate video codec context\n");
return;
}
/* put sample parameters */
(*enc_ctx)->bit_rate = 100000;
/* resolution must be a multiple of two */
(*enc_ctx)->width = width;
(*enc_ctx)->height = height;
/* frames per second */
(*enc_ctx)->time_base = (AVRational){1,25};
(*enc_ctx)->framerate = (AVRational){25,1};
/* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
(*enc_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;
(*enc_ctx)->codec_id = codec_mpeg1->id;
(*enc_ctx)->codec_type = AVMEDIA_TYPE_VIDEO;
(*enc_ctx)->gop_size = 20;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
ofmt_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if(avcodec_open2((*enc_ctx),codec_mpeg1,nullptr) < 0)
{
printf("avcodec_open2 fail.\n");
}
nRet = avcodec_parameters_from_context(stream->codecpar,(*enc_ctx));
if(nRet < 0)
{
printf("avcodec_parameters_to_context fail.");
return ;
}
return;
}
static void openAudioEncoder( AVCodecContext** enc_ctx,
AVFormatContext **ofmt_ctx,
AVStream *in_stream_a)
{
int nRet = 0;
AVStream *stream = nullptr;
//音频不做转码,使用和输入音频流一样的解码器
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
if(!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
if (!(stream = avformat_new_stream(*ofmt_ctx, codec)))
{
fprintf(stderr, "Could not allocate video codec context\n");
return;
}
(*enc_ctx) = avcodec_alloc_context3(codec);
if ((* enc_ctx) == nullptr)
{
fprintf(stderr, "Could not allocate video codec context\n");
return;
}
//Copy the settings of AVCodecContext
if (avcodec_parameters_to_context((* enc_ctx),in_stream_a->codecpar)< 0) {
printf( "Failed to copy context from input to output stream codec context\n");
return ;
}
if(avcodec_open2((*enc_ctx),codec,nullptr) < 0)
{
printf("avcodec_open2 fail.\n");
}
stream->codecpar->codec_tag = 0;
if ((*ofmt_ctx)->oformat->flags & AVFMT_GLOBALHEADER)
{
(*enc_ctx)->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
//将AVCodecContext的成员复制到AVCodecParameters结构体。前后两行不能调换顺序
avcodec_parameters_from_context(stream->codecpar, (* enc_ctx));
return;
}
static void open_input(const char* pInFileName,
AVFormatContext **pInFmtCtx,
AVCodecContext** pInCodecCtx_v,
AVCodecContext** pInCodecCtx_a)
{
int nRet = 0;
AVDictionary *pDic = nullptr;
nRet = avformat_open_input(pInFmtCtx,pInFileName,nullptr,&pDic);
if( nRet < 0)
{
printf("Could not open input file.");
return;
}
avformat_find_stream_info(*pInFmtCtx, nullptr);
printf("===========Input Information==========\n");
av_dump_format(*pInFmtCtx, 0, pInFileName, 0);
printf("======================================\n");
for (int i = 0; i < (*pInFmtCtx)->nb_streams; i++)
{
if((*pInFmtCtx)->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
nVideoStream_idx_in = i;
AVStream * in_stream_v = (*pInFmtCtx)->streams[i];
AVCodec *pInCodec_v = avcodec_find_decoder(in_stream_v->codecpar->codec_id);
if(nullptr == pInCodec_v)
{
printf("inpout video avcodec_find_decoder fail.");
return;
}
*pInCodecCtx_v = avcodec_alloc_context3(pInCodec_v);
nRet = avcodec_parameters_to_context(*pInCodecCtx_v, in_stream_v->codecpar);
if(nRet < 0)
{
printf("avcodec_parameters_to_context fail.");
return;
}
//打开视频解码器
if(avcodec_open2(*pInCodecCtx_v, pInCodec_v, nullptr) < 0)
{
printf("Error: Can't open codec!\n");
return ;
}
if(nRet < 0)
{
printf("avcodec_parameters_from_context fail.");
return;
}
printf("width = %d\n", (*pInCodecCtx_v)->width);
printf("height = %d\n",(*pInCodecCtx_v)->height);
if(nRet < 0)
{
printf("inpout video avcodec_parameters_to_context fail.");
return;
}
}
if((*pInFmtCtx)->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
nAudioStream_idx_in = i;
AVStream * in_stream_a = (*pInFmtCtx)->streams[i];
AVCodec *pInCodec_a = avcodec_find_decoder(in_stream_a->codecpar->codec_id);
if(nullptr == pInCodec_a)
{
printf("inpout audio avcodec_find_decoder fail.\n");
return;
}
*pInCodecCtx_a = avcodec_alloc_context3(pInCodec_a);
nRet = avcodec_parameters_to_context(*pInCodecCtx_a, in_stream_a->codecpar);
if(nRet < 0)
{
printf("avcodec_parameters_to_context fail.\n");
return;
}
if(nRet < 0)
{
printf("avcodec_parameters_from_context fail.\n");
return;
}
//打开音频解码器
if(avcodec_open2(*pInCodecCtx_a, pInCodec_a, nullptr) < 0)
{
printf("Error: Can't open codec!\n");
return ;
}
}
}
}
static void open_output(const char* pOutFileName,
AVCodecContext* pInCodecCtx_v,
AVCodecContext* pInCodecCtx_a,
AVFormatContext** ofmt_ctx,
AVCodecContext** encVideoCtx,
AVCodecContext** encAudioctx,
AVStream *in_stream_a)
{
AVOutputFormat *ofmt = nullptr;
//Output
avformat_alloc_output_context2(ofmt_ctx, nullptr, nullptr, pOutFileName);
if (!ofmt_ctx) {
printf( "Could not create output context\n");
return ;
}
openVidoEncoder_mpg1video(pInCodecCtx_v->width,pInCodecCtx_v->height,*ofmt_ctx,encVideoCtx);
openAudioEncoder(encAudioctx,ofmt_ctx,in_stream_a);
ofmt = (*ofmt_ctx)->oformat;
//Open output file
if (!(ofmt->flags & AVFMT_NOFILE))
{
if (avio_open(&(*ofmt_ctx)->pb, pOutFileName, AVIO_FLAG_WRITE) < 0)
{
printf( "Could not open output file '%s'", pOutFileName);
return ;
}
}
printf("==========Output Information==========\n");
av_dump_format(*ofmt_ctx, 0, pOutFileName, 1);
printf("======================================\n");
}
static void test()
{
int nRet = 0;
const char *pInFileName = "D:/videos/new_killer.flv";
const char *pOutFileName = "D:/videos/_new_killer.mp4";
AVFormatContext *pInFmtCtx = nullptr;
AVFormatContext *ofmt_ctx = nullptr;
AVCodecContext* encVideoCtx = nullptr;
AVCodecContext* encAudioctx = nullptr;
AVCodecContext* pInCodecCtx_v = nullptr;
AVCodecContext* pInCodecCtx_a = nullptr;
int got_picture = 0;
AVPacket pkt;
AVPacket newpkt;
av_init_packet(&pkt);
av_init_packet(&newpkt);
AVFrame *pFrame = av_frame_alloc();
open_input(pInFileName,
&pInFmtCtx,
&pInCodecCtx_v,
&pInCodecCtx_a);
AVStream * in_stream_a = pInFmtCtx->streams[nAudioStream_idx_in];
open_output(pOutFileName,
pInCodecCtx_v,
pInCodecCtx_a,
&ofmt_ctx,
&encVideoCtx,
&encAudioctx,
in_stream_a);
//Write file header
nRet = avformat_write_header(ofmt_ctx, nullptr);
if ( nRet < 0)
{
printf( "Error occurred when opening output file\n");
return ;
}
while (1)
{
AVStream *in_stream = nullptr;
AVStream *out_stream= nullptr;
//读取一帧到pkt,视频是1帧,音频可能1帧或者多帧
nRet = av_read_frame(pInFmtCtx, &pkt);
if( nRet < 0)
{
printf( "av_read_frame end \n");
break ;
}
if(pkt.stream_index == nVideoStream_idx_in)
{
//把pkt发送给解码器pInCodecCtx_v解码(后台进行)
nRet = avcodec_send_packet(pInCodecCtx_v, &pkt);
if(nRet <0 )
{
av_packet_unref(&pkt);
std::cout<<"avcodec_send_packet fail \n";
break;
}
//从pInCodecCtx_v获取解码好的原始数据到pFrame
got_picture =avcodec_receive_frame(pInCodecCtx_v, pFrame);
if(0 == got_picture)//转码
{
//送pFrame原始数据给编码器进行编码
nRet = avcodec_send_frame(encVideoCtx,pFrame);
if(nRet < 0)
{
printf("avcodec_send_frame fail.\n");
return;
}
//从编码器获取编号的数据
while(nRet >= 0)
{
//编码好的数据发送到newpkt
nRet = avcodec_receive_packet(encVideoCtx,&newpkt);
//返回值为-11意味着需要新的输入数据才能返回新的输出。
//在解码或编码开始时,编解码器可能会接收多个输入帧/数据包而不返回帧,直到其内部缓冲区被填充为止。
if( AVERROR(EAGAIN) == nRet || AVERROR_EOF == nRet)
{
av_packet_unref(&newpkt);
break;
}
else if(nRet < 0 )
{
printf("avcodec_receive_packet fail.\n");
return;
}
//转换PTS/DTS(Convert PTS/DTS)
in_stream = pInFmtCtx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
newpkt.pts = av_rescale_q_rnd(newpkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
newpkt.dts = av_rescale_q_rnd(newpkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
newpkt.duration = av_rescale_q(newpkt.duration, in_stream->time_base, out_stream->time_base);
newpkt.pos = -1;
printf("video Write 1 Packet. size:%5d\tpts:%lld\n",pkt.size,pkt.pts);
//写入(Write)
nRet = av_interleaved_write_frame(ofmt_ctx, &newpkt);
if (nRet < 0)
{
printf( "Error muxing packet\n");
break;
}
av_packet_unref(&newpkt);
}
}
}
else if(pkt.stream_index == nAudioStream_idx_in)
{
//转换PTS/DTS(Convert PTS/DTS)
in_stream = pInFmtCtx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
/* copy packet */
//转换PTS/DTS(Convert PTS/DTS)
AVRational temp1 = in_stream->time_base;
AVRational temp2 = out_stream->time_base;
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
printf("audio Write 1 Packet. size:%5d\tpts:%lld\n",pkt.size,pkt.pts);
//写入(Write)
nRet = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (nRet < 0)
{
printf( "Error muxing packet\n");
break;
}
}
av_packet_unref(&pkt);
}
//Write file trailer
av_write_trailer(ofmt_ctx);
printf( "av_write_trailer \n");
printf( "==================================================== \n");
av_dump_format(ofmt_ctx, 0, pOutFileName, 1);
printf( "==================================================== \n");
avformat_close_input(&pInFmtCtx);
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
}
int main()
{
test();
std::cout<<"end";
}
标签:ffmpeg,stream,avcodec,nRet,ctx,filter,transcode,printf,ofmt 来源: https://blog.csdn.net/asdasfdgdhh/article/details/111316934