Audio 在MPEG-TS上使用libavcodec对视频进行转码并复制音频
我正在尝试使用Audio 在MPEG-TS上使用libavcodec对视频进行转码并复制音频,audio,video,ffmpeg,libavcodec,libavformat,Audio,Video,Ffmpeg,Libavcodec,Libavformat,我正在尝试使用libavcodec来降低MPEG传输流的视频比特率,同时保持音频流不变。等效的ffmpeg命令行是: ffmpeg-i SPTS_HD_2min.prog.ts-b:v 800k-s cif-map 0:0-map 0:1-map 0:2-c:a副本。/transcodeCLI.ts 输入文件包含: Input #0, mpegts, from 'SPTS_HD_2min.program8.ts': Duration: 00:02:01.56 bitrate: 10579 kb/
libavcodec
来降低MPEG传输流的视频比特率,同时保持音频流不变。等效的ffmpeg
命令行是:
ffmpeg-i SPTS_HD_2min.prog.ts-b:v 800k-s cif-map 0:0-map 0:1-map 0:2-c:a副本。/transcodeCLI.ts
输入文件包含:
Input #0, mpegts, from 'SPTS_HD_2min.program8.ts': Duration: 00:02:01.56 bitrate: 10579 kb/s
Program 1
Stream #0:0[0x21]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(tv, bt709, top first), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
Stream #0:1[0x61](eng): Audio: ac3 (AC-3 / 0x332D4341), 48000 Hz, 5.1(side), fltp, 384 kb/s
Stream #0:2[0x63](eng): Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, stereo, s16p, 192 kb/s
使用,程序不会生成有效的传输流。但是,该文件不会播放。此外,分析工具显示文件持续时间几乎是原来的两倍。有点不对
程序很简单:在循环中读取、编码、写入。视频流的编解码器上下文设置为较低的比特率和宽度/高度
我已经修补了很长一段时间没有成功,但是我设置的任何东西都没有达到预期的效果
下面是非常概括的资料来源。(为了简洁起见,我删除了变量defs、错误检查和调试消息)
编辑
在那之后,我已经包括了完整的、可编译的源代码
编辑II
MPEG-TS测试文件可以从
typedef struct StreamContext
{
AVCodecContext*decodecctx;
AVCodecContext*encodeCtx;
}StreamContext;
静态StreamContext*streamCtx;
静态整数
openInputFile(常量字符*文件名)
{
inFormatCtx=NULL;
ret=avformat\u open\u输入(&inFormatCtx,filename,NULL,NULL);
ret=avformat\u find\u stream\u info(inFormatCtx,NULL)
streamCtx=av_mallocz_数组(inFormatCtx->nb_流,sizeof(*streamCtx));
对于(i=0;inb\u流;i++)
{
AVStream*stream=inFormatCtx->streams[i];
AVCodec*dec=AVCodec\u find\u解码器(流->编解码器->编解码器id);
AVCodecContext*pCodecCtx=avcodec\u alloc\u context3(dec);
ret=avcodec_参数_到_上下文(pCodecCtx,stream->codepar);
如果(pCodecCtx->codec_type==AVMEDIA_type|VIDEO | pCodecCtx->codec_type==AVMEDIA_type_AUDIO)
{
如果(pCodecCtx->codec\u type==AVMEDIA\u type\u VIDEO)
pCodecCtx->framerate=av_guess_frame_rate(inFormatCtx,stream,NULL);
/*开放式解码器*/
ret=avcodec_open2(pCodecCtx,dec,NULL);
}
streamCtx[i].decodeCtx=pCodecCtx;
}
返回0;
}
静态整数
openOutputFile(常量字符*文件名)
{
outFormatCtx=NULL;
avformat_alloc_output_context2(&outFormatCtx,NULL,NULL,filename);
对于(i=0;inb\u流;i++)
{
out_stream=avformat_new_stream(outFormatCtx,NULL);
in_stream=inFormatCtx->streams[i];
decodeCtx=streamCtx[i].decodeCtx;
如果(decodeCtx->codec_type==AVMEDIA_type|VIDEO | decodeCtx->codec_type==AVMEDIA_type_AUDIO)
{
编码器=avcodec\u find\u编码器(decodeCtx->codec\u id);
pEncodeCtx=avcodec\u alloc\u context3(编码器);
如果(解码CTX->编解码器类型==AVMEDIA\u类型\u视频)
{
//小一点!
pEncodeCtx->height=decodeCtx->height/4;
pEncodeCtx->width=decodeCtx->width/4;
pEncodeCtx->sample\u aspect\u ratio=decodeCtx->sample\u aspect\u ratio;
//也许这些也可以?
pEncodeCtx->比特率=700000;
pEncodeCtx->比特率公差=0;
pEncodeCtx->framerate=decodeCtx->framerate;
pEncodeCtx->time\u base=decodeCtx->time\u base;
/*从支持的格式列表中获取第一种格式*/
if(编码器->pix_fmts)
pEncodeCtx->pix_fmt=编码器->pix_fmts[0];
其他的
pEncodeCtx->pix_fmt=decodeCtx->pix_fmt;
/*视频时间_基地可以设置为任何方便和编码器支持*/
pEncodeCtx->time\u base=av\u inv\u q(decodeCtx->framerate);
}
其他的
{
pEncodeCtx->sample\u rate=decodeCtx->sample\u rate;
pEncodeCtx->channel\u layout=decodeCtx->channel\u layout;
pEncodeCtx->channels=av\u get\u channel\u layout\u nb\u channels(pEncodeCtx->channel\u layout);
/*从支持的格式列表中获取第一种格式*/
pEncodeCtx->sample_fmt=编码器->sample_fmts[0];
pEncodeCtx->time_base=(AVRational){1,pEncodeCtx->sample_rate};
}
ret=avcodec_open2(pEncodeCtx,编码器,空);
ret=avcodec\u参数\u来自\u上下文(out\u stream->codecpar,pEncodeCtx);
if(outFormatCtx->oformat->flags和AVFMT_GLOBALHEADER)
pEncodeCtx->flags |=AV_编解码器_FLAG_全局_头;
out\u stream->time\u base=pEncodeCtx->time\u base;
streamCtx[i].encodeCtx=pEncodeCtx;
}
else if(decodeCtx->codec\u type==AVMEDIA\u type\u未知)
返回AVERROR_INVALIDDATA;
其他的
{
/*如果必须对该流进行重推*/
ret=avcodec\u参数\u复制(输出流->编解码器,输入流->编解码器);
出流->时基=入流->时基;
}
}
av_转储_格式(outFormatCtx,0,文件名,1);
如果(!(格式转换->格式->标志和AVFMT_文件))
ret=avio_open(&outFormatCtx->pb,文件名,avio_标志_WRITE);
/*初始化muxer,写入输出文件头*/
ret=avformat\U write\U头(格式外发送,空);
返回0;
}
静态整数
encodeAndWriteFrame(AVFrame*inFrame,unsigned int streamIndex,int*pGotFrame)
{
encodedPkt.data=NULL;
encodedPkt.size=0;
av_init_包(&encodedPkt);
int codecType=inFormatCtx->streams[streamIndex]->codecpar->codec\u类型;
if(codecType==AVMEDIA\u TYPE\u VIDEO)
ret=avcodec_encode_video2(streamCtx[streamIndex].encodeCtx和encodedPkt、inFrame、pGotFrame);
其他的
ret=avcodec\u encode\u audio2(streamCtx[streamIndex].encodeCtx
typedef struct StreamContext
{
AVCodecContext *decodeCtx;
AVCodecContext *encodeCtx;
} StreamContext;
static StreamContext *streamCtx;
static int
openInputFile(const char *filename)
{
inFormatCtx = NULL;
ret = avformat_open_input(&inFormatCtx, filename, NULL, NULL);
ret = avformat_find_stream_info(inFormatCtx, NULL)
streamCtx = av_mallocz_array(inFormatCtx->nb_streams, sizeof(*streamCtx));
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
AVStream *stream = inFormatCtx->streams[i];
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id);
AVCodecContext *pCodecCtx = avcodec_alloc_context3(dec);
ret = avcodec_parameters_to_context(pCodecCtx, stream->codecpar);
if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO || pCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO)
{
if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO)
pCodecCtx->framerate = av_guess_frame_rate(inFormatCtx, stream, NULL);
/* Open decoder */
ret = avcodec_open2(pCodecCtx, dec, NULL);
}
streamCtx[i].decodeCtx = pCodecCtx;
}
return 0;
}
static int
openOutputFile(const char *filename)
{
outFormatCtx = NULL;
avformat_alloc_output_context2(&outFormatCtx, NULL, NULL, filename);
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
out_stream = avformat_new_stream(outFormatCtx, NULL);
in_stream = inFormatCtx->streams[i];
decodeCtx = streamCtx[i].decodeCtx;
if (decodeCtx->codec_type == AVMEDIA_TYPE_VIDEO || decodeCtx->codec_type == AVMEDIA_TYPE_AUDIO)
{
encoder = avcodec_find_encoder(decodeCtx->codec_id);
pEncodeCtx = avcodec_alloc_context3(encoder);
if (decodeCtx->codec_type == AVMEDIA_TYPE_VIDEO)
{
// MAKE IT SMALLER!
pEncodeCtx->height = decodeCtx->height / 4;
pEncodeCtx->width = decodeCtx->width / 4;
pEncodeCtx->sample_aspect_ratio = decodeCtx->sample_aspect_ratio;
// perhaps set these too?
pEncodeCtx->bit_rate = 700000;
pEncodeCtx->bit_rate_tolerance = 0;
pEncodeCtx->framerate = decodeCtx->framerate;
pEncodeCtx->time_base = decodeCtx->time_base;
/* take first format from list of supported formats */
if (encoder->pix_fmts)
pEncodeCtx->pix_fmt = encoder->pix_fmts[0];
else
pEncodeCtx->pix_fmt = decodeCtx->pix_fmt;
/* video time_base can be set to whatever is handy and supported by encoder */
pEncodeCtx->time_base = av_inv_q(decodeCtx->framerate);
}
else
{
pEncodeCtx->sample_rate = decodeCtx->sample_rate;
pEncodeCtx->channel_layout = decodeCtx->channel_layout;
pEncodeCtx->channels = av_get_channel_layout_nb_channels(pEncodeCtx->channel_layout);
/* take first format from list of supported formats */
pEncodeCtx->sample_fmt = encoder->sample_fmts[0];
pEncodeCtx->time_base = (AVRational) { 1, pEncodeCtx->sample_rate };
}
ret = avcodec_open2(pEncodeCtx, encoder, NULL);
ret = avcodec_parameters_from_context(out_stream->codecpar, pEncodeCtx);
if (outFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
pEncodeCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
out_stream->time_base = pEncodeCtx->time_base;
streamCtx[i].encodeCtx = pEncodeCtx;
}
else if (decodeCtx->codec_type == AVMEDIA_TYPE_UNKNOWN)
return AVERROR_INVALIDDATA;
else
{
/* if this stream must be remuxed */
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
out_stream->time_base = in_stream->time_base;
}
}
av_dump_format(outFormatCtx, 0, filename, 1);
if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE))
ret = avio_open(&outFormatCtx->pb, filename, AVIO_FLAG_WRITE);
/* init muxer, write output file header */
ret = avformat_write_header(outFormatCtx, NULL);
return 0;
}
static int
encodeAndWriteFrame(AVFrame *inFrame, unsigned int streamIndex, int *pGotFrame)
{
encodedPkt.data = NULL;
encodedPkt.size = 0;
av_init_packet(&encodedPkt);
int codecType = inFormatCtx->streams[streamIndex]->codecpar->codec_type;
if (codecType == AVMEDIA_TYPE_VIDEO)
ret = avcodec_encode_video2(streamCtx[streamIndex].encodeCtx, &encodedPkt, inFrame, pGotFrame);
else
ret = avcodec_encode_audio2(streamCtx[streamIndex].encodeCtx, &encodedPkt, inFrame, pGotFrame);
if (*pGotFrame == 0)
return 0;
/* prepare packet for muxing */
encodedPkt.stream_index = streamIndex;
av_packet_rescale_ts(&encodedPkt, streamCtx[streamIndex].encodeCtx->time_base, outFormatCtx->streams[streamIndex]->time_base);
/* mux encoded frame */
ret = av_interleaved_write_frame(outFormatCtx, &encodedPkt);
return ret;
}
int
main(int argc, char **argv)
{
av_register_all();
avfilter_register_all();
if ((ret = openInputFile(argv[1])) < 0)
goto end;
if ((ret = openOutputFile(argv[2])) < 0)
goto end;
/* read all packets */
while (1)
{
if ((ret = av_read_frame(inFormatCtx, &packet)) < 0)
break;
readPktNum++;
streamIndex = packet.stream_index;
type = inFormatCtx->streams[packet.stream_index]->codecpar->codec_type;
av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n", streamIndex);
if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)
{
pDecFrame = av_frame_alloc();
av_packet_rescale_ts(&packet, inFormatCtx->streams[streamIndex]->time_base, streamCtx[streamIndex].decodeCtx->time_base);
if (type == AVMEDIA_TYPE_VIDEO)
ret = avcodec_decode_video2(streamCtx[streamIndex].decodeCtx, pDecFrame, &gotDecFrame, &packet);
else
ret = avcodec_decode_audio4(streamCtx[streamIndex].decodeCtx, pDecFrame, &gotDecFrame, &packet);
if (gotDecFrame)
{
pDecFrame->pts = av_frame_get_best_effort_timestamp(pDecFrame);
ret = encodeAndWriteFrame(pDecFrame, streamIndex, 0);
av_frame_free(&pDecFrame);
if (ret < 0)
goto end;
}
else
av_frame_free(&pDecFrame);
}
else
{
/* remux this frame without reencoding */
av_packet_rescale_ts(&packet, inFormatCtx->streams[streamIndex]->time_base, outFormatCtx->streams[streamIndex]->time_base);
ret = av_interleaved_write_frame(outFormatCtx, &packet);
if (ret < 0)
goto end;
}
av_packet_unref(&packet);
}
/* flush encoders */
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
/* flush encoder */
ret = flushEncoder(i);
}
av_write_trailer(outFormatCtx);
end:
av_packet_unref(&packet);
av_frame_free(&pDecFrame);
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
avcodec_free_context(&streamCtx[i].decodeCtx);
if (outFormatCtx && outFormatCtx->nb_streams > i && outFormatCtx->streams[i] && streamCtx[i].encodeCtx)
avcodec_free_context(&streamCtx[i].encodeCtx);
}
av_free(streamCtx);
avformat_close_input(&inFormatCtx);
if (outFormatCtx && !(outFormatCtx->oformat->flags & AVFMT_NOFILE))
avio_closep(&outFormatCtx->pb);
avformat_free_context(outFormatCtx);
return ret ? 1 : 0;
}
/**
* @file
* API example for demuxing, decoding, filtering, encoding and muxing
* @example transcoding.c
*/
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_PINK "\x1b[31;1m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_LIME "\x1b[32;1m"
#define ANSI_COLOR_YELLOW "\x1b[33;1m"
#define ANSI_COLOR_BLUE "\x1b[34;1m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36;1m"
#define ANSI_COLOR_RESET "\x1b[0m"
#define true 1
#define false 0
static int readPktNum = 0;
static int decFrameNum = 0;
static int encFrameNum = 0;
static AVFormatContext *inFormatCtx;
static AVFormatContext *outFormatCtx;
typedef struct StreamContext
{
AVCodecContext *decodeCtx;
AVCodecContext *encodeCtx;
} StreamContext;
static StreamContext *streamCtx;
void
writeAVFrameAsYUVFile(const char *filePath, AVFrame *pFrame)
{
printf("Writing YUV file: %d x %d\n", pFrame->width, pFrame->height);
FILE *pFile = fopen(filePath, "wb");
if (!pFile)
return;
int y;
// Writing Y
for (y=0; y < pFrame->height; y++)
fwrite(&pFrame->data[0][pFrame->linesize[0] * y], pFrame->width, 1, pFile);
// Writing U
for (y=0; y < pFrame->height/2; y++)
fwrite(&pFrame->data[1][pFrame->linesize[1] * y], pFrame->width/2, 1, pFile);
// Writing V
for (y=0; y < pFrame->height/2; y++)
fwrite(&pFrame->data[2][pFrame->linesize[2] * y], pFrame->width/2, 1, pFile);
fclose(pFile);
printf("Wrote %s: %d x %d\n", filePath, pFrame->width, pFrame->height);
}
static void
dumpCodecContext(const AVCodecContext *pCodecContext)
{
printf("Codec Context:\n");
printf(" bit rate %d\n", (int)pCodecContext->bit_rate);
printf(" bit rate tolerance %d\n", pCodecContext->bit_rate_tolerance);
printf(" size %d x %d\n", pCodecContext->width, pCodecContext->height);
printf(" GOP Size %d\n", pCodecContext->gop_size);
printf(" Max B Frames %d\n", pCodecContext->max_b_frames);
printf(" Sample Aspect %d:%d (%.3f)\n",
pCodecContext->sample_aspect_ratio.num, pCodecContext->sample_aspect_ratio.den,
1.0 * pCodecContext->sample_aspect_ratio.num / pCodecContext->sample_aspect_ratio.den);
printf(" framerate %d / %d (%.3f fps)\n",
pCodecContext->framerate.num, pCodecContext->framerate.den,
1.0 * pCodecContext->framerate.den / pCodecContext->framerate.num);
printf(" time_base %d / %d (%.3f fps)\n",
pCodecContext->time_base.num, pCodecContext->time_base.den,
1.0 * pCodecContext->time_base.den / pCodecContext->time_base.num);
}
static int
openInputFile(const char *filename)
{
int ret;
unsigned int i;
inFormatCtx = NULL;
if ((ret = avformat_open_input(&inFormatCtx, filename, NULL, NULL)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
return ret;
}
if ((ret = avformat_find_stream_info(inFormatCtx, NULL)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
return ret;
}
streamCtx = av_mallocz_array(inFormatCtx->nb_streams, sizeof(*streamCtx));
if (!streamCtx)
return AVERROR(ENOMEM);
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
AVStream *stream = inFormatCtx->streams[i];
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id);
AVCodecContext *pCodecCtx;
if (!dec)
{
av_log(NULL, AV_LOG_ERROR, "Failed to find decoder for stream #%u\n", i);
return AVERROR_DECODER_NOT_FOUND;
}
pCodecCtx = avcodec_alloc_context3(dec);
if (!pCodecCtx)
{
av_log(NULL, AV_LOG_ERROR, "Failed to allocate the decoder context for stream #%u\n", i);
return AVERROR(ENOMEM);
}
ret = avcodec_parameters_to_context(pCodecCtx, stream->codecpar);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Failed to copy decoder parameters to input decoder context for stream #%u\n", i);
return ret;
}
/* Reencode video & audio and remux subtitles etc. */
if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO || pCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO)
{
if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO)
pCodecCtx->framerate = av_guess_frame_rate(inFormatCtx, stream, NULL);
/* Open decoder */
ret = avcodec_open2(pCodecCtx, dec, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);
return ret;
}
}
streamCtx[i].decodeCtx = pCodecCtx;
}
av_dump_format(inFormatCtx, 0, filename, 0);
return 0;
}
static int
openOutputFile(const char *filename)
{
AVStream *out_stream;
AVStream *in_stream;
AVCodecContext *decodeCtx, *pEncodeCtx;
AVCodec *encoder;
int ret;
unsigned int i;
outFormatCtx = NULL;
avformat_alloc_output_context2(&outFormatCtx, NULL, NULL, filename);
if (!outFormatCtx)
{
av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
return AVERROR_UNKNOWN;
}
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
out_stream = avformat_new_stream(outFormatCtx, NULL);
if (!out_stream)
{
av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
return AVERROR_UNKNOWN;
}
in_stream = inFormatCtx->streams[i];
decodeCtx = streamCtx[i].decodeCtx;
if (decodeCtx->codec_type == AVMEDIA_TYPE_VIDEO || decodeCtx->codec_type == AVMEDIA_TYPE_AUDIO)
{
/* in this example, we choose transcoding to same codec */
encoder = avcodec_find_encoder(decodeCtx->codec_id);
if (!encoder)
{
av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
return AVERROR_INVALIDDATA;
}
pEncodeCtx = avcodec_alloc_context3(encoder);
if (!pEncodeCtx)
{
av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");
return AVERROR(ENOMEM);
}
/* In this example, we transcode to same properties (picture size,
* sample rate etc.). These properties can be changed for output
* streams easily using filters */
if (decodeCtx->codec_type == AVMEDIA_TYPE_VIDEO)
{
printf("DECODE CONTEXT "); dumpCodecContext(decodeCtx);
// MAKE IT SMALLER!
pEncodeCtx->height = decodeCtx->height / 4;
pEncodeCtx->width = decodeCtx->width / 4;
pEncodeCtx->sample_aspect_ratio = decodeCtx->sample_aspect_ratio;
// perhaps set these too?
pEncodeCtx->bit_rate = 700000;
pEncodeCtx->bit_rate_tolerance = 0;
pEncodeCtx->framerate = decodeCtx->framerate;
pEncodeCtx->time_base = decodeCtx->time_base;
printf("ENCODE CONTEXT "); dumpCodecContext(pEncodeCtx);
/* take first format from list of supported formats */
if (encoder->pix_fmts)
pEncodeCtx->pix_fmt = encoder->pix_fmts[0];
else
pEncodeCtx->pix_fmt = decodeCtx->pix_fmt;
/* video time_base can be set to whatever is handy and supported by encoder */
pEncodeCtx->time_base = av_inv_q(decodeCtx->framerate);
}
else
{
pEncodeCtx->sample_rate = decodeCtx->sample_rate;
pEncodeCtx->channel_layout = decodeCtx->channel_layout;
pEncodeCtx->channels = av_get_channel_layout_nb_channels(pEncodeCtx->channel_layout);
/* take first format from list of supported formats */
pEncodeCtx->sample_fmt = encoder->sample_fmts[0];
pEncodeCtx->time_base = (AVRational) { 1, pEncodeCtx->sample_rate };
}
/* Third parameter can be used to pass settings to encoder */
ret = avcodec_open2(pEncodeCtx, encoder, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
return ret;
}
ret = avcodec_parameters_from_context(out_stream->codecpar, pEncodeCtx);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", i);
return ret;
}
if (outFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
pEncodeCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
out_stream->time_base = pEncodeCtx->time_base;
streamCtx[i].encodeCtx = pEncodeCtx;
}
else if (decodeCtx->codec_type == AVMEDIA_TYPE_UNKNOWN)
{
av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
return AVERROR_INVALIDDATA;
}
else
{
printf("STREAM %d is not video or audio\n", i);
/* if this stream must be remuxed */
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Copying parameters for stream #%u failed\n", i);
return ret;
}
out_stream->time_base = in_stream->time_base;
}
}
av_dump_format(outFormatCtx, 0, filename, 1);
if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE))
{
ret = avio_open(&outFormatCtx->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
return ret;
}
}
/* init muxer, write output file header */
ret = avformat_write_header(outFormatCtx, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
return ret;
}
return 0;
}
static int
encodeAndWriteFrame(AVFrame *inFrame, unsigned int streamIndex, int *pGotFrame)
{
int ret;
int got_frame_local;
AVPacket encodedPkt;
if (pGotFrame == 0)
pGotFrame = &got_frame_local;
encodedPkt.data = NULL;
encodedPkt.size = 0;
av_init_packet(&encodedPkt);
int codecType = inFormatCtx->streams[streamIndex]->codecpar->codec_type;
if (codecType == AVMEDIA_TYPE_VIDEO)
ret = avcodec_encode_video2(streamCtx[streamIndex].encodeCtx, &encodedPkt, inFrame, pGotFrame);
else
ret = avcodec_encode_audio2(streamCtx[streamIndex].encodeCtx, &encodedPkt, inFrame, pGotFrame);
if (ret < 0)
return ret;
if (*pGotFrame == 0)
return 0;
if (encFrameNum++ % 10 == 0)
printf("Encoded %s frame #%d\n", (codecType == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio", encFrameNum);
/* prepare packet for muxing */
encodedPkt.stream_index = streamIndex;
av_packet_rescale_ts(&encodedPkt, streamCtx[streamIndex].encodeCtx->time_base, outFormatCtx->streams[streamIndex]->time_base);
av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
/* mux encoded frame */
ret = av_interleaved_write_frame(outFormatCtx, &encodedPkt);
return ret;
}
static int
flushEncoder(unsigned int streamIndex)
{
int ret;
int got_frame;
if (!(streamCtx[streamIndex].encodeCtx->codec->capabilities & AV_CODEC_CAP_DELAY))
return 0;
while (1)
{
av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encoder\n", streamIndex);
ret = encodeAndWriteFrame(NULL, streamIndex, &got_frame);
if (ret < 0)
break;
if (!got_frame)
return 0;
}
return ret;
}
int
main(int argc, char **argv)
{
int ret;
AVPacket packet = { .data = NULL, .size = 0 };
AVFrame *pDecFrame = NULL;
enum AVMediaType type;
unsigned int streamIndex;
unsigned int i;
int gotDecFrame;
if (argc != 3)
{
av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
return 1;
}
av_register_all();
avfilter_register_all();
if ((ret = openInputFile(argv[1])) < 0)
goto end;
if ((ret = openOutputFile(argv[2])) < 0)
goto end;
/* read all packets */
while (1)
{
if ((ret = av_read_frame(inFormatCtx, &packet)) < 0)
{
printf(ANSI_COLOR_YELLOW "READ PACKET RETURNED %d\n" ANSI_COLOR_RESET, ret);
break;
}
readPktNum++;
streamIndex = packet.stream_index;
type = inFormatCtx->streams[packet.stream_index]->codecpar->codec_type;
av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n", streamIndex);
if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)
{
pDecFrame = av_frame_alloc();
if (!pDecFrame)
{
ret = AVERROR(ENOMEM);
break;
}
av_packet_rescale_ts(&packet, inFormatCtx->streams[streamIndex]->time_base, streamCtx[streamIndex].decodeCtx->time_base);
if (type == AVMEDIA_TYPE_VIDEO)
ret = avcodec_decode_video2(streamCtx[streamIndex].decodeCtx, pDecFrame, &gotDecFrame, &packet);
else
ret = avcodec_decode_audio4(streamCtx[streamIndex].decodeCtx, pDecFrame, &gotDecFrame, &packet);
if (ret < 0)
{
av_frame_free(&pDecFrame);
av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
break;
}
if (gotDecFrame)
{
if (decFrameNum++ % 10 == 0)
printf("Decoded %s frame #%d\n", (type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio", decFrameNum);
if (0 && type == AVMEDIA_TYPE_VIDEO)
{
printf("VIDEO width %d height %d\n", pDecFrame->width, pDecFrame->height);
writeAVFrameAsYUVFile("/mnt/swdevel/DVStor/decodedYUV.yuv", pDecFrame);
}
pDecFrame->pts = av_frame_get_best_effort_timestamp(pDecFrame);
ret = encodeAndWriteFrame(pDecFrame, streamIndex, 0);
av_frame_free(&pDecFrame);
if (ret < 0)
goto end;
}
else
av_frame_free(&pDecFrame);
}
else
{
/* remux this frame without reencoding */
av_packet_rescale_ts(&packet, inFormatCtx->streams[streamIndex]->time_base, outFormatCtx->streams[streamIndex]->time_base);
ret = av_interleaved_write_frame(outFormatCtx, &packet);
if (ret < 0)
goto end;
}
av_packet_unref(&packet);
}
printf(ANSI_COLOR_YELLOW "EXIT MAIN WHILE(1) - FLUSHING\n" ANSI_COLOR_RESET);
/* flush encoders */
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
/* flush encoder */
ret = flushEncoder(i);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Flushing encoder failed\n");
goto end;
}
}
av_write_trailer(outFormatCtx);
end:
av_packet_unref(&packet);
av_frame_free(&pDecFrame);
for (i = 0; i < inFormatCtx->nb_streams; i++)
{
avcodec_free_context(&streamCtx[i].decodeCtx);
if (outFormatCtx && outFormatCtx->nb_streams > i && outFormatCtx->streams[i] && streamCtx[i].encodeCtx)
avcodec_free_context(&streamCtx[i].encodeCtx);
}
av_free(streamCtx);
avformat_close_input(&inFormatCtx);
if (outFormatCtx && !(outFormatCtx->oformat->flags & AVFMT_NOFILE))
avio_closep(&outFormatCtx->pb);
avformat_free_context(outFormatCtx);
if (ret < 0)
av_log(NULL, AV_LOG_ERROR, "Error occurred: %s\n", av_err2str(ret));
return ret ? 1 : 0;
}