|
|
@ -39,7 +39,6 @@ static StreamContext *stream_ctx; |
|
|
|
static int open_input_file(const char *filename) |
|
|
|
static int open_input_file(const char *filename) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
ifmt_ctx = nullptr; |
|
|
|
ifmt_ctx = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
if ((ret = avformat_open_input(&ifmt_ctx, filename, nullptr, nullptr)) < 0) { |
|
|
|
if ((ret = avformat_open_input(&ifmt_ctx, filename, nullptr, nullptr)) < 0) { |
|
|
@ -57,7 +56,7 @@ static int open_input_file(const char *filename) |
|
|
|
if (!stream_ctx) |
|
|
|
if (!stream_ctx) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
for (int i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
AVStream *stream = ifmt_ctx->streams[i]; |
|
|
|
AVStream *stream = ifmt_ctx->streams[i]; |
|
|
|
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id); |
|
|
|
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id); |
|
|
|
AVCodecContext *codec_ctx; |
|
|
|
AVCodecContext *codec_ctx; |
|
|
@ -76,7 +75,7 @@ static int open_input_file(const char *filename) |
|
|
|
"for stream #%u\n", i); |
|
|
|
"for stream #%u\n", i); |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
/* Reencode video & audio and remux subtitles etc. */ |
|
|
|
/* encode video & audio and remux subtitles etc. */ |
|
|
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO |
|
|
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO |
|
|
|
|| codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { |
|
|
|
|| codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { |
|
|
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) |
|
|
|
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) |
|
|
@ -102,7 +101,6 @@ static int open_output_file(const char *filename) |
|
|
|
AVCodecContext *dec_ctx, *enc_ctx; |
|
|
|
AVCodecContext *dec_ctx, *enc_ctx; |
|
|
|
AVCodec *encoder; |
|
|
|
AVCodec *encoder; |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ofmt_ctx = nullptr; |
|
|
|
ofmt_ctx = nullptr; |
|
|
|
avformat_alloc_output_context2(&ofmt_ctx, nullptr, nullptr, filename); |
|
|
|
avformat_alloc_output_context2(&ofmt_ctx, nullptr, nullptr, filename); |
|
|
@ -111,7 +109,7 @@ static int open_output_file(const char *filename) |
|
|
|
return AVERROR_UNKNOWN; |
|
|
|
return AVERROR_UNKNOWN; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
for (int i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
out_stream = avformat_new_stream(ofmt_ctx, nullptr); |
|
|
|
out_stream = avformat_new_stream(ofmt_ctx, nullptr); |
|
|
|
if (!out_stream) { |
|
|
|
if (!out_stream) { |
|
|
|
ALOGE("Failed allocating output stream\n"); |
|
|
|
ALOGE("Failed allocating output stream\n"); |
|
|
@ -135,9 +133,8 @@ static int open_output_file(const char *filename) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* In this example, we transcode to same properties (picture size,
|
|
|
|
/* we transcode to same properties (picture size, sample rate etc.).
|
|
|
|
* sample rate etc.). These properties can be changed for output |
|
|
|
* These properties can be changed for output streams using filters */ |
|
|
|
* streams easily using filters */ |
|
|
|
|
|
|
|
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { |
|
|
|
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { |
|
|
|
enc_ctx->height = dec_ctx->height; |
|
|
|
enc_ctx->height = dec_ctx->height; |
|
|
|
enc_ctx->width = dec_ctx->width; |
|
|
|
enc_ctx->width = dec_ctx->width; |
|
|
@ -179,7 +176,6 @@ static int open_output_file(const char *filename) |
|
|
|
ALOGE("Elementary stream #%d is of unknown type, cannot proceed\n", i); |
|
|
|
ALOGE("Elementary stream #%d is of unknown type, cannot proceed\n", i); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* if this stream must be remuxed */ |
|
|
|
|
|
|
|
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); |
|
|
|
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); |
|
|
|
if (ret < 0) { |
|
|
|
if (ret < 0) { |
|
|
|
ALOGE("Copying parameters for stream #%u failed\n", i); |
|
|
|
ALOGE("Copying parameters for stream #%u failed\n", i); |
|
|
@ -389,7 +385,7 @@ static int init_filters() |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) { |
|
|
|
static int encode_write_frame(AVFrame *filt_frame, int stream_index, int *got_frame) { |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
int got_frame_local; |
|
|
|
int got_frame_local; |
|
|
|
AVPacket enc_pkt; |
|
|
|
AVPacket enc_pkt; |
|
|
@ -400,13 +396,10 @@ static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, in |
|
|
|
if (!got_frame) |
|
|
|
if (!got_frame) |
|
|
|
got_frame = &got_frame_local; |
|
|
|
got_frame = &got_frame_local; |
|
|
|
|
|
|
|
|
|
|
|
ALOGE("Encoding frame\n"); |
|
|
|
|
|
|
|
/* encode filtered frame */ |
|
|
|
|
|
|
|
enc_pkt.data = nullptr; |
|
|
|
enc_pkt.data = nullptr; |
|
|
|
enc_pkt.size = 0; |
|
|
|
enc_pkt.size = 0; |
|
|
|
av_init_packet(&enc_pkt); |
|
|
|
av_init_packet(&enc_pkt); |
|
|
|
ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt, |
|
|
|
ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt, filt_frame, got_frame); |
|
|
|
filt_frame, got_frame); |
|
|
|
|
|
|
|
av_frame_free(&filt_frame); |
|
|
|
av_frame_free(&filt_frame); |
|
|
|
if (ret < 0) |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
@ -419,18 +412,16 @@ static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, in |
|
|
|
stream_ctx[stream_index].enc_ctx->time_base, |
|
|
|
stream_ctx[stream_index].enc_ctx->time_base, |
|
|
|
ofmt_ctx->streams[stream_index]->time_base); |
|
|
|
ofmt_ctx->streams[stream_index]->time_base); |
|
|
|
|
|
|
|
|
|
|
|
ALOGE("Muxing frame\n"); |
|
|
|
|
|
|
|
/* mux encoded frame */ |
|
|
|
/* mux encoded frame */ |
|
|
|
ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt); |
|
|
|
ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt); |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index) |
|
|
|
static int filter_encode_write_frame(AVFrame *frame, int stream_index) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
AVFrame *filt_frame; |
|
|
|
AVFrame *filter_frame; |
|
|
|
|
|
|
|
|
|
|
|
ALOGE("Pushing decoded frame to filters\n"); |
|
|
|
|
|
|
|
/* push the decoded frame into the filtergraph */ |
|
|
|
/* push the decoded frame into the filtergraph */ |
|
|
|
ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx, |
|
|
|
ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx, |
|
|
|
frame, 0); |
|
|
|
frame, 0); |
|
|
@ -441,27 +432,21 @@ static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index) |
|
|
|
|
|
|
|
|
|
|
|
/* pull filtered frames from the filtergraph */ |
|
|
|
/* pull filtered frames from the filtergraph */ |
|
|
|
while (1) { |
|
|
|
while (1) { |
|
|
|
filt_frame = av_frame_alloc(); |
|
|
|
filter_frame = av_frame_alloc(); |
|
|
|
if (!filt_frame) { |
|
|
|
if (!filter_frame) { |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
ALOGE("Pulling filtered frame from filters\n"); |
|
|
|
ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx, filter_frame); |
|
|
|
ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx, |
|
|
|
|
|
|
|
filt_frame); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
if (ret < 0) { |
|
|
|
/* if no more frames for output - returns AVERROR(EAGAIN)
|
|
|
|
|
|
|
|
* if flushed and no more frames for output - returns AVERROR_EOF |
|
|
|
|
|
|
|
* rewrite retcode to 0 to show it as normal procedure completion |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) |
|
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) |
|
|
|
ret = 0; |
|
|
|
ret = 0; |
|
|
|
av_frame_free(&filt_frame); |
|
|
|
av_frame_free(&filter_frame); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
filt_frame->pict_type = AV_PICTURE_TYPE_NONE; |
|
|
|
filter_frame->pict_type = AV_PICTURE_TYPE_NONE; |
|
|
|
ret = encode_write_frame(filt_frame, stream_index, nullptr); |
|
|
|
ret = encode_write_frame(filter_frame, stream_index, nullptr); |
|
|
|
if (ret < 0) |
|
|
|
if (ret < 0) |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -469,7 +454,7 @@ static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index) |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int flush_encoder(unsigned int stream_index) |
|
|
|
static int flush_encoder(int stream_index) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
int got_frame; |
|
|
|
int got_frame; |
|
|
@ -479,7 +464,7 @@ static int flush_encoder(unsigned int stream_index) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
while (1) { |
|
|
|
ALOGE("Flushing stream #%u encoder\n", stream_index); |
|
|
|
ALOGE("Flushing stream #%d encoder\n", stream_index); |
|
|
|
ret = encode_write_frame(nullptr, stream_index, &got_frame); |
|
|
|
ret = encode_write_frame(nullptr, stream_index, &got_frame); |
|
|
|
if (ret < 0) |
|
|
|
if (ret < 0) |
|
|
|
break; |
|
|
|
break; |
|
|
@ -495,8 +480,8 @@ int transcode(const char *input_file, const char *output_file) |
|
|
|
AVPacket packet = { .data = nullptr, .size = 0 }; |
|
|
|
AVPacket packet = { .data = nullptr, .size = 0 }; |
|
|
|
AVFrame *frame = nullptr; |
|
|
|
AVFrame *frame = nullptr; |
|
|
|
enum AVMediaType type; |
|
|
|
enum AVMediaType type; |
|
|
|
unsigned int stream_index; |
|
|
|
int stream_index; |
|
|
|
unsigned int i; |
|
|
|
int i; |
|
|
|
int got_frame; |
|
|
|
int got_frame; |
|
|
|
int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *); |
|
|
|
int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *); |
|
|
|
|
|
|
|
|
|
|
@ -513,11 +498,8 @@ int transcode(const char *input_file, const char *output_file) |
|
|
|
break; |
|
|
|
break; |
|
|
|
stream_index = packet.stream_index; |
|
|
|
stream_index = packet.stream_index; |
|
|
|
type = ifmt_ctx->streams[packet.stream_index]->codecpar->codec_type; |
|
|
|
type = ifmt_ctx->streams[packet.stream_index]->codecpar->codec_type; |
|
|
|
ALOGE("Demuxer gave frame of stream_index %u\n", |
|
|
|
|
|
|
|
stream_index); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filter_ctx[stream_index].filter_graph) { |
|
|
|
if (filter_ctx && filter_ctx[stream_index].filter_graph) { |
|
|
|
ALOGE("Going to re-encode&filter the frame\n"); |
|
|
|
|
|
|
|
frame = av_frame_alloc(); |
|
|
|
frame = av_frame_alloc(); |
|
|
|
if (!frame) { |
|
|
|
if (!frame) { |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
@ -559,8 +541,7 @@ int transcode(const char *input_file, const char *output_file) |
|
|
|
|
|
|
|
|
|
|
|
/* flush filters and encoders */ |
|
|
|
/* flush filters and encoders */ |
|
|
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
for (i = 0; i < ifmt_ctx->nb_streams; i++) { |
|
|
|
/* flush filter */ |
|
|
|
if (!filter_ctx || !filter_ctx[i].filter_graph) |
|
|
|
if (!filter_ctx[i].filter_graph) |
|
|
|
|
|
|
|
continue; |
|
|
|
continue; |
|
|
|
ret = filter_encode_write_frame(nullptr, i); |
|
|
|
ret = filter_encode_write_frame(nullptr, i); |
|
|
|
if (ret < 0) { |
|
|
|
if (ret < 0) { |
|
|
@ -568,7 +549,6 @@ int transcode(const char *input_file, const char *output_file) |
|
|
|
goto end; |
|
|
|
goto end; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* flush encoder */ |
|
|
|
|
|
|
|
ret = flush_encoder(i); |
|
|
|
ret = flush_encoder(i); |
|
|
|
if (ret < 0) { |
|
|
|
if (ret < 0) { |
|
|
|
ALOGE("Flushing encoder failed\n"); |
|
|
|
ALOGE("Flushing encoder failed\n"); |
|
|
@ -587,7 +567,8 @@ end: |
|
|
|
if (filter_ctx && filter_ctx[i].filter_graph) |
|
|
|
if (filter_ctx && filter_ctx[i].filter_graph) |
|
|
|
avfilter_graph_free(&filter_ctx[i].filter_graph); |
|
|
|
avfilter_graph_free(&filter_ctx[i].filter_graph); |
|
|
|
} |
|
|
|
} |
|
|
|
av_free(filter_ctx); |
|
|
|
if (filter_ctx) |
|
|
|
|
|
|
|
av_free(filter_ctx); |
|
|
|
av_free(stream_ctx); |
|
|
|
av_free(stream_ctx); |
|
|
|
avformat_close_input(&ifmt_ctx); |
|
|
|
avformat_close_input(&ifmt_ctx); |
|
|
|
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) |
|
|
|
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) |
|
|
|