基于QT+FFMPEG的音视频开发(五)——转码2
我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
https://blog.csdn.net/leixiaohua1020/article/details/42658139
转码,就是将一个不需要的格式转换成为自己需要的格式。
上次研究不带编解码的转码,这次是带编解码的,经过解码后重新编码变换格式。
本次实验把avi转码为mp4。
一、输入初始化
// 1.初始化输入ic
AVFormatContext *ic = avformat_alloc_context();
if(avformat_open_input(&ic, in_file, 0, 0) != 0)
{
cout << "can not open file : " << in_file << endl;
return -1;
}
if(avformat_find_stream_info(ic, 0) < 0)
{
cout << "no stream information" << endl;
return -1;
}
av_dump_format(ic, 0, in_file, 0);
二、寻找音视频流
这步比较简单,利用for循环遍历就好
// 2.寻找音视频流
unsigned int i;
for(i = 0; i < ic->nb_streams; i++)
{
if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
vIndex = i;
else if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
aIndex = i;
}
三、解码器
寻找并打开解码器
1. 视频解码器
AVCodec *v_dec = avcodec_find_decoder(ic->streams[vIndex]->codecpar->codec_id);
AVCodecContext *vDec = avcodec_alloc_context3(v_dec);
avcodec_parameters_to_context(vDec, ic->streams[vIndex]->codecpar);
if(avcodec_open2(vDec, v_dec, 0) != 0)
{
cout << "can not open video decoder" << endl;
return -1;
}
2. 音频解码器
AVCodec *a_dec = avcodec_find_decoder(ic->streams[aIndex]->codecpar->codec_id);
AVCodecContext *aDec = avcodec_alloc_context3(a_dec);
avcodec_parameters_to_context(aDec, ic->streams[aIndex]->codecpar);
if(avcodec_open2(aDec, a_dec, 0) != 0)
{
cout << "can not open audio decoder" << endl;
return -1;
}
四、编码器
寻找、设置并打开编码器
1. 视频编码器
AVCodec *v_enc = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
AVCodecContext *vEnc = avcodec_alloc_context3(v_enc);
vEnc->codec_id = AV_CODEC_ID_MPEG4;
vEnc->codec_type = AVMEDIA_TYPE_VIDEO;
vEnc->pix_fmt = AV_PIX_FMT_YUV420P;
vEnc->width = 800;
vEnc->height =600;
vEnc->time_base.num = 1;
vEnc->time_base.den = 25;
vEnc->bit_rate = 468000;
vEnc->gop_size = 250;
vEnc->qmin = 10;
vEnc->qmax = 51;
vEnc->max_b_frames = 0;
if (avcodec_open2(vEnc, v_enc, 0) < 0)
{
cout << "can not open video encoder" << endl;
return -1;
}
2. 音频编码器
AVCodec *a_enc = avcodec_find_encoder(AV_CODEC_ID_MP3);
AVCodecContext *aEnc = avcodec_alloc_context3(a_enc);
aEnc->codec_id = AV_CODEC_ID_MP3;
aEnc->codec_type = AVMEDIA_TYPE_AUDIO;
aEnc->sample_fmt = AV_SAMPLE_FMT_S16P;
aEnc->channel_layout = AV_CH_LAYOUT_STEREO;
aEnc->bit_rate = 64000;
aEnc->sample_rate = 44100;
aEnc->channels = 2;
if (avcodec_open2(aEnc, a_enc, 0) < 0)
{
cout << "can not open audio encoder" << endl;
return -1;
}
五、输出初始化
AVFormatContext *oc;
avformat_alloc_output_context2(&oc, NULL, "mp4", path);
if(oc == NULL)
{
cout << "creat output context failed" << endl;
return -1;
}
六、创建输出流、复制
AVStream *vStream = avformat_new_stream(oc, v_enc);
if(vStream == NULL)
{
cout << "creat video stream failed" << endl;
return -1;
}
AVStream *aStream = avformat_new_stream(oc, a_enc);
if(aStream == NULL)
{
cout << "creat audio stream failed" << endl;
return -1;
}
vStream->codecpar->codec_tag = 0;
if(avcodec_parameters_from_context(vStream->codecpar, vEnc) < 0)
{
cout << "copy video context failed" << endl;
return -1;
}
aStream->codecpar->codec_tag = 0;
if(avcodec_parameters_from_context(aStream->codecpar, aEnc) < 0)
{
cout << "copy audio context failed" << endl;
return -1;
}
七、输出控制
if(avio_open(&oc->pb, path, AVIO_FLAG_WRITE) < 0)
{
cout << "open output file failed" << endl;
return -1;
}
av_dump_format(oc, 0, path, 1);
八、视频scale和音频sample
SwsContext *enc_sws = sws_alloc_context();
enc_sws = sws_getCachedContext(enc_sws, vDec->width, vDec->height, vEnc->pix_fmt,
vEnc->width, vEnc->height, vEnc->pix_fmt,
SWS_BICUBIC, 0, 0, 0);
SwrContext *enc_swr = swr_alloc();
enc_swr = swr_alloc_set_opts(enc_swr, aEnc->channel_layout, aEnc->sample_fmt,
aEnc->sample_rate, aDec->channel_layout,
aDec->sample_fmt, aDec->sample_rate, 0, 0);
swr_init(enc_swr);
九、核心解码、编码
//解码
ret = avcodec_send_packet(vDec, dec_pkt);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
ret = avcodec_receive_frame(vDec, frame);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//解码结束
sws_scale(enc_sws, (const uint8_t* const*)frame->data, frame->linesize,
0, vDec->height, yuv->data, yuv->linesize);
//编码
ret = avcodec_send_frame(vEnc, yuv);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
while(!ret)
{
ret = avcodec_receive_packet(vEnc, enc_pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//pts,dts设置
enc_pkt->stream_index = vStream->index;
AVStream *in_stream = ic->streams[vIndex];
AVRational time_base = in_stream->time_base;
AVRational r_framerate1 = in_stream->r_frame_rate;
AVRational time_base_q = { 1, AV_TIME_BASE };
int64_t calc_duration = (double)(AV_TIME_BASE) / av_q2d(r_framerate1);
enc_pkt->pts = av_rescale_q(dec_pkt->pts * calc_duration,
time_base_q,
time_base);
enc_pkt->dts = enc_pkt->pts;
enc_pkt->duration = av_rescale_q(calc_duration,
time_base_q,
time_base);
enc_pkt->pos = -1;
{
int64_t pts_time = av_rescale_q(enc_pkt->dts,
time_base,
time_base_q);
int64_t now_time = av_gettime() - start_time;
if (pts_time > now_time)
av_usleep(pts_time - now_time);
}
enc_pkt->pts = av_rescale_q_rnd(enc_pkt->pts,
in_stream->time_base,
vStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->dts = av_rescale_q_rnd(enc_pkt->dts,
in_stream->time_base,
vStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->duration = av_rescale_q(enc_pkt->duration,
in_stream->time_base,
vStream->time_base);
//写入文件
av_interleaved_write_frame(oc, enc_pkt);
}
下载地址:https://download.csdn.net/download/mr__hu/11255840
修改不了下载积分,还是
附源码
设计是面向过程的,当然,感兴趣的可以设计为面向对象
int main()
{
avformat_network_init();
int ret, vIndex = -1, aIndex = -1;
const char *in_file = "E:/workspace/my.avi";
const char *path = "out.avi";
// 1.初始化输入ic
AVFormatContext *ic = avformat_alloc_context();
if(avformat_open_input(&ic, in_file, 0, 0) != 0)
{
cout << "can not open file : " << in_file << endl;
return -1;
}
if(avformat_find_stream_info(ic, 0) < 0)
{
cout << "no stream information" << endl;
return -1;
}
av_dump_format(ic, 0, in_file, 0);
// 2.寻找音视频流
unsigned int i;
for(i = 0; i < ic->nb_streams; i++)
{
if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
vIndex = i;
else if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
aIndex = i;
}
if(vIndex == -1)
{
cout << "no video stream" << endl;
}
if(aIndex == -1)
{
cout << "no audio stream" << endl;
}
// 3.寻找视频解码器
AVCodec *v_dec = avcodec_find_decoder(ic->streams[vIndex]->codecpar->codec_id);
if(v_dec == NULL)
{
cout << "no video decoder" << endl;
return -1;
}
AVCodecContext *vDec = avcodec_alloc_context3(v_dec);
if(avcodec_parameters_to_context(vDec, ic->streams[vIndex]->codecpar) < 0)
{
cout << "can not copy video codec" << endl;
return -1;
}
// 4.打开视频解码器
if(avcodec_open2(vDec, v_dec, 0) != 0)
{
cout << "can not open video decoder" << endl;
return -1;
}
// 5.寻找音频解码器
AVCodec *a_dec = avcodec_find_decoder(ic->streams[aIndex]->codecpar->codec_id);
if(a_dec == NULL)
{
cout << "no audio decoder" << endl;
return -1;
}
AVCodecContext *aDec = avcodec_alloc_context3(a_dec);
ret = avcodec_parameters_to_context(aDec, ic->streams[aIndex]->codecpar);
if(ret < 0)
{
cout << "can not copy audio codec" << endl;
return -1;
}
// 6.打开音频解码器
if(avcodec_open2(aDec, a_dec, 0) != 0)
{
cout << "can not open audio decoder" << endl;
return -1;
}
// 7.寻找视频编码器
AVCodec *v_enc = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
if(v_enc == NULL)
{
cout << "no video encoder" << endl;
return -1;
}
AVCodecContext *vEnc = avcodec_alloc_context3(v_enc);
if(vEnc == NULL)
{
cout << "can not creat video codec" << endl;
return -1;
}
vEnc->codec_id = AV_CODEC_ID_MPEG4;
vEnc->codec_type = AVMEDIA_TYPE_VIDEO;
vEnc->pix_fmt = AV_PIX_FMT_YUV420P;
vEnc->width = 800;
vEnc->height =600;
vEnc->time_base.num = 1;
vEnc->time_base.den = 25;
vEnc->bit_rate = 468000;
vEnc->gop_size = 250;
vEnc->qmin = 10;
vEnc->qmax = 51;
vEnc->max_b_frames = 0;
// 8.打开视频编码器
if (avcodec_open2(vEnc, v_enc, 0) < 0)
{
cout << "can not open video encoder" << endl;
return -1;
}
// 9.查找音频编码器
AVCodec *a_enc = avcodec_find_encoder(AV_CODEC_ID_MP3);
if(a_enc == NULL)
{
cout << "no audio encoder" << endl;
return -1;
}
AVCodecContext *aEnc = avcodec_alloc_context3(a_enc);
if(aEnc == NULL)
{
cout << "can not creat audio codec" << endl;
return -1;
}
aEnc->codec_id = AV_CODEC_ID_MP3;
aEnc->codec_type = AVMEDIA_TYPE_AUDIO;
aEnc->sample_fmt = AV_SAMPLE_FMT_S16P;
aEnc->channel_layout = AV_CH_LAYOUT_STEREO;
aEnc->bit_rate = 64000;
aEnc->sample_rate = 44100;
aEnc->channels = 2;
// 10.打开音频编码器
if (avcodec_open2(aEnc, a_enc, 0) < 0)
{
cout << "can not open audio encoder" << endl;
return -1;
}
// 11.初始化输出oc
AVFormatContext *oc;
avformat_alloc_output_context2(&oc, NULL, "mpegts", path);
if(oc == NULL)
{
cout << "creat output context failed" << endl;
return -1;
}
// 12.创建输出流
AVStream *vStream = avformat_new_stream(oc, v_enc);
if(vStream == NULL)
{
cout << "creat video stream failed" << endl;
return -1;
}
AVStream *aStream = avformat_new_stream(oc, a_enc);
if(aStream == NULL)
{
cout << "creat audio stream failed" << endl;
return -1;
}
// 13.复制视编码上下文
vStream->codecpar->codec_tag = 0;
if(avcodec_parameters_from_context(vStream->codecpar, vEnc) < 0)
{
cout << "copy video context failed" << endl;
return -1;
}
aStream->codecpar->codec_tag = 0;
if(avcodec_parameters_from_context(aStream->codecpar, aEnc) < 0)
{
cout << "copy audio context failed" << endl;
return -1;
}
// 14.打开输出控制
if(avio_open(&oc->pb, path, AVIO_FLAG_WRITE) < 0)
{
cout << "open output file failed" << endl;
return -1;
}
av_dump_format(oc, 0, path, 1);
// 15.转码上下文
SwsContext *enc_sws = sws_alloc_context();
enc_sws = sws_getCachedContext(enc_sws, vDec->width, vDec->height, vEnc->pix_fmt,
vEnc->width, vEnc->height, vEnc->pix_fmt,
SWS_BICUBIC, 0, 0, 0);
SwrContext *enc_swr = swr_alloc();
enc_swr = swr_alloc_set_opts(enc_swr, aEnc->channel_layout, aEnc->sample_fmt,
aEnc->sample_rate, aDec->channel_layout,
aDec->sample_fmt, aDec->sample_rate, 0, 0);
swr_init(enc_swr);
// 16.初始化存储位置
AVFrame *yuv = av_frame_alloc();
yuv->width = vEnc->width;
yuv->height = vEnc->height;
yuv->format = vEnc->pix_fmt;
av_frame_get_buffer(yuv, 0);
AVFrame *pcm = av_frame_alloc();
pcm->format = aEnc->sample_fmt;
pcm->nb_samples = aEnc->frame_size;
pcm->channel_layout = aEnc->channel_layout;
av_frame_get_buffer(pcm, 0);
AVPacket *dec_pkt = (AVPacket*)av_malloc(sizeof(AVPacket)); //解码前pkt
AVPacket *enc_pkt = (AVPacket*)av_malloc(192000 * 4); //编码后pkt
AVFrame *frame = av_frame_alloc(); //解码暂存
avformat_write_header(oc, NULL);
int64_t start_time = av_gettime();
int64_t frameIndex = 0;
for(;;)
{
if(av_read_frame(ic, dec_pkt) >= 0)
{
frameIndex = dec_pkt->pts;
if(dec_pkt->stream_index == vIndex)
{
//解码
ret = avcodec_send_packet(vDec, dec_pkt);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
ret = avcodec_receive_frame(vDec, frame);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//解码结束
cout << "decode 1 video frame ok" << endl;
sws_scale(enc_sws, (const uint8_t* const*)frame->data, frame->linesize,
0, vDec->height, yuv->data, yuv->linesize);
//编码
ret = avcodec_send_frame(vEnc, yuv);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
while(!ret)
{
ret = avcodec_receive_packet(vEnc, enc_pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//pts,dts设置
enc_pkt->stream_index = vStream->index;
AVStream *in_stream = ic->streams[vIndex];
AVRational time_base = in_stream->time_base;
AVRational r_framerate1 = in_stream->r_frame_rate;
AVRational time_base_q = { 1, AV_TIME_BASE };
int64_t calc_duration = (double)(AV_TIME_BASE) / av_q2d(r_framerate1);
enc_pkt->pts = av_rescale_q(dec_pkt->pts * calc_duration,
time_base_q,
time_base);
enc_pkt->dts = enc_pkt->pts;
enc_pkt->duration = av_rescale_q(calc_duration,
time_base_q,
time_base);
enc_pkt->pos = -1;
{
int64_t pts_time = av_rescale_q(enc_pkt->dts,
time_base,
time_base_q);
int64_t now_time = av_gettime() - start_time;
if (pts_time > now_time)
av_usleep(pts_time - now_time);
}
enc_pkt->pts = av_rescale_q_rnd(enc_pkt->pts,
in_stream->time_base,
vStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->dts = av_rescale_q_rnd(enc_pkt->dts,
in_stream->time_base,
vStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->duration = av_rescale_q(enc_pkt->duration,
in_stream->time_base,
vStream->time_base);
//写入文件
av_interleaved_write_frame(oc, enc_pkt);
cout << "encode 1 video frame ok" << endl;
av_packet_unref(enc_pkt);
}
}
else if(dec_pkt->stream_index == aIndex)
{
//解码
ret = avcodec_send_packet(aDec, dec_pkt);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
ret = avcodec_receive_frame(aDec, frame);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//解码结束
cout << "decode 1 audio frame ok" << endl;
AVAudioFifo *fifo = av_audio_fifo_alloc(aEnc->sample_fmt, aEnc->channels,
aEnc->frame_size);
int finishFlag = 0;
while(av_audio_fifo_size(fifo) < aEnc->frame_size)
{
uint8_t ** audioBuffer = NULL;
av_samples_alloc_array_and_samples(&audioBuffer, NULL,
aEnc->channels, frame->nb_samples,
aEnc->sample_fmt, 1);
swr_convert(enc_swr, audioBuffer, frame->nb_samples,
(const uint8_t**)frame->data, frame->nb_samples);
av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame->nb_samples);
av_audio_fifo_write(fifo, (void**)audioBuffer, frame->nb_samples);
if(audioBuffer)
{
av_free(audioBuffer[0]);
av_free(audioBuffer);
}
else
{
finishFlag = 1;
break;
}
}
while(av_audio_fifo_size(fifo) >= aEnc->frame_size ||
(finishFlag == 1 && av_audio_fifo_size(fifo) > 0))
{
int size = FFMIN(av_audio_fifo_size(fifo), aEnc->frame_size);
pcm->nb_samples = size;
pcm->channel_layout = aEnc->channel_layout;
pcm->sample_rate = aEnc->sample_rate;
pcm->format = aEnc->sample_fmt;
av_frame_get_buffer(pcm, 0);
av_audio_fifo_read(fifo, (void**)pcm->data, pcm->nb_samples);
}
if(finishFlag == 1 && av_audio_fifo_size(fifo) == 0)
av_audio_fifo_free(fifo);
//编码
ret = avcodec_send_frame(aEnc, pcm);
if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
while(!ret)
{
ret = avcodec_receive_packet(aEnc, enc_pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//pts,dts设置
enc_pkt->stream_index = aStream->index;
AVStream *in_stream = ic->streams[aIndex];
AVRational time_base1 = in_stream->time_base;
AVRational time_base_q = { 1, AV_TIME_BASE };
double frame_size = in_stream->codecpar->frame_size;
double sample_rate = in_stream->codecpar->sample_rate;
int64_t calc_duration=(double)(AV_TIME_BASE) * (frame_size/sample_rate);
enc_pkt->pts = av_rescale_q(dec_pkt->pts * calc_duration,
time_base_q,
time_base1);
enc_pkt->dts = enc_pkt->pts;
enc_pkt->duration = av_rescale_q(calc_duration,
time_base_q,
time_base1);
enc_pkt->pos = -1;
enc_pkt->pts = av_rescale_q_rnd(enc_pkt->pts,
in_stream->time_base,
aStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->dts = av_rescale_q_rnd(enc_pkt->dts,
in_stream->time_base,
aStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->duration = av_rescale_q(enc_pkt->duration,
in_stream->time_base,
aStream->time_base);
//写入文件
av_interleaved_write_frame(oc, enc_pkt);
cout << "encode 1 audio frame ok" << endl;
av_packet_unref(enc_pkt);
}
}
av_packet_unref(dec_pkt);
}
else
break;
}
while(1)
{
frameIndex++;
ret = avcodec_send_frame(aEnc, NULL);
if(ret < 0)
{
cout << "ret = " << ret << endl;
break;
}
while(!ret)
{
ret = avcodec_receive_packet(aEnc, enc_pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if(ret < 0)
{
cout << "ret = " << ret << endl;
return -1;
}
//pts,dts设置
enc_pkt->stream_index = aStream->index;
AVStream *in_stream = ic->streams[aIndex];
AVRational time_base1 = in_stream->time_base;
AVRational time_base_q = { 1, AV_TIME_BASE };
double frame_size = in_stream->codecpar->frame_size;
double sample_rate = in_stream->codecpar->sample_rate;
int64_t calc_duration=(double)(AV_TIME_BASE) * (frame_size/sample_rate);
enc_pkt->pts = av_rescale_q(frameIndex * calc_duration,
time_base_q,
time_base1);
enc_pkt->dts = enc_pkt->pts;
enc_pkt->duration = av_rescale_q(calc_duration,
time_base_q,
time_base1);
enc_pkt->pos = -1;
enc_pkt->pts = av_rescale_q_rnd(enc_pkt->pts,
in_stream->time_base,
aStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->dts = av_rescale_q_rnd(enc_pkt->dts,
in_stream->time_base,
aStream->time_base,
(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
enc_pkt->duration = av_rescale_q(enc_pkt->duration,
in_stream->time_base,
aStream->time_base);
//写入文件
av_interleaved_write_frame(oc, enc_pkt);
cout << "finish encode 1 audio frame ok" << endl;
av_packet_unref(enc_pkt);
}
}
av_write_trailer(oc);
av_frame_free(&frame);
av_frame_free(&yuv);
av_frame_free(&pcm);
avcodec_free_context(&vDec);
avcodec_free_context(&vEnc);
avcodec_free_context(&aDec);
avcodec_free_context(&aEnc);
sws_freeContext(enc_sws);
swr_free(&enc_swr);
avformat_close_input(&ic);
avio_close(oc->pb);
avformat_free_context(oc);
cout << "Hello World!" << endl;
return 0;
}