/*
* avconv main
- * Copyright (c) 2000-2011 The libav developers.
+ * Copyright (c) 2000-2011 The Libav developers
*
* This file is part of Libav.
*
}
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
- AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
- while (bsfc) {
- AVBitStreamFilterContext *next = bsfc->next;
- av_bitstream_filter_close(bsfc);
- bsfc = next;
- }
- ost->bitstream_filters = NULL;
+
+ for (j = 0; j < ost->nb_bitstream_filters; j++)
+ av_bsf_free(&ost->bsf_ctx[j]);
+ av_freep(&ost->bsf_ctx);
+ av_freep(&ost->bitstream_filters);
+
av_frame_free(&ost->filtered_frame);
av_parser_close(ost->parser);
exit_program(1);
}
-static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+static void write_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
{
AVStream *st = ost->st;
- AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
int ret;
/*
}
}
- while (bsfc) {
- AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec;
- AVPacket new_pkt = *pkt;
- int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
- &new_pkt.data, &new_pkt.size,
- pkt->data, pkt->size,
- pkt->flags & AV_PKT_FLAG_KEY);
- if (a > 0) {
- av_packet_unref(pkt);
- new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
- av_buffer_default_free, NULL, 0);
- if (!new_pkt.buf)
- exit_program(1);
- } else if (a < 0) {
- av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
- bsfc->filter->name, pkt->stream_index,
- avctx->codec ? avctx->codec->name : "copy");
- print_error("", a);
- if (exit_on_error)
- exit_program(1);
- }
- *pkt = new_pkt;
-
- bsfc = bsfc->next;
- }
-
if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
ost->last_mux_dts != AV_NOPTS_VALUE &&
pkt->dts < ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT)) {
}
}
+static void output_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+{
+ int ret = 0;
+
+ /* apply the output bitstream filters, if any */
+ if (ost->nb_bitstream_filters) {
+ int idx;
+
+ ret = av_bsf_send_packet(ost->bsf_ctx[0], pkt);
+ if (ret < 0)
+ goto finish;
+
+ idx = 1;
+ while (idx) {
+ /* get a packet from the previous filter up the chain */
+ ret = av_bsf_receive_packet(ost->bsf_ctx[idx - 1], pkt);
+ if (ret == AVERROR(EAGAIN)) {
+ ret = 0;
+ idx--;
+ continue;
+ } else if (ret < 0)
+ goto finish;
+
+ /* send it to the next filter down the chain or to the muxer */
+ if (idx < ost->nb_bitstream_filters) {
+ ret = av_bsf_send_packet(ost->bsf_ctx[idx], pkt);
+ if (ret < 0)
+ goto finish;
+ idx++;
+ } else
+ write_packet(s, pkt, ost);
+ }
+ } else
+ write_packet(s, pkt, ost);
+
+finish:
+ if (ret < 0 && ret != AVERROR_EOF) {
+ av_log(NULL, AV_LOG_FATAL, "Error applying bitstream filters to an output "
+ "packet for stream #%d:%d.\n", ost->file_index, ost->index);
+ exit_program(1);
+ }
+}
+
static int check_recording_time(OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
{
AVCodecContext *enc = ost->enc_ctx;
AVPacket pkt;
- int got_packet = 0;
+ int ret;
av_init_packet(&pkt);
pkt.data = NULL;
ost->samples_encoded += frame->nb_samples;
ost->frames_encoded++;
- if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
+ ret = avcodec_send_frame(enc, frame);
+ if (ret < 0)
+ goto error;
+
+ while (1) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret == AVERROR(EAGAIN))
+ break;
+ if (ret < 0)
+ goto error;
- if (got_packet) {
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(s, &pkt, ost);
+ output_packet(s, &pkt, ost);
}
+
+ return;
+error:
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
}
static void do_subtitle_out(AVFormatContext *s,
else
pkt.pts += 90 * sub->end_display_time;
}
- write_frame(s, &pkt, ost);
+ output_packet(s, &pkt, ost);
}
}
AVFrame *in_picture,
int *frame_size)
{
- int ret, format_video_sync, got_packet;
+ int ret, format_video_sync;
AVPacket pkt;
AVCodecContext *enc = ost->enc_ctx;
ost->frames_encoded++;
- ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
- exit_program(1);
- }
+ ret = avcodec_send_frame(enc, in_picture);
+ if (ret < 0)
+ goto error;
+
+ /*
+ * For video, there may be reordering, so we can't throw away frames on
+ * encoder flush, we need to limit them here, before they go into encoder.
+ */
+ ost->frame_number++;
+
+ while (1) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret == AVERROR(EAGAIN))
+ break;
+ if (ret < 0)
+ goto error;
- if (got_packet) {
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(s, &pkt, ost);
+ output_packet(s, &pkt, ost);
*frame_size = pkt.size;
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
+
+ ost->sync_opts++;
}
- ost->sync_opts++;
- /*
- * For video, number of frames in == number of packets out.
- * But there may be reordering, so we can't throw away frames on encoder
- * flush, we need to limit them here, before they go into encoder.
- */
- ost->frame_number++;
+ return;
+error:
+ av_assert0(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF);
+ av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+ exit_program(1);
}
static double psnr(double d)
if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
continue;
+ if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+
+ avcodec_send_frame(enc, NULL);
+
for (;;) {
- int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
- const char *desc;
+ const char *desc = NULL;
switch (enc->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- encode = avcodec_encode_audio2;
desc = "Audio";
break;
case AVMEDIA_TYPE_VIDEO:
- encode = avcodec_encode_video2;
desc = "Video";
break;
default:
- stop_encoding = 1;
+ av_assert0(0);
}
- if (encode) {
+ if (1) {
AVPacket pkt;
- int got_packet;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
- ret = encode(enc, &pkt, NULL, &got_packet);
- if (ret < 0) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret < 0 && ret != AVERROR_EOF) {
av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
exit_program(1);
}
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
- if (!got_packet) {
+ if (ret == AVERROR_EOF) {
stop_encoding = 1;
break;
}
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(os, &pkt, ost);
+ output_packet(os, &pkt, ost);
}
if (stop_encoding)
opkt.size = pkt->size;
}
- write_frame(of->ctx, &opkt, ost);
+ output_packet(of->ctx, &opkt, ost);
+}
+
+// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
+// There is the following difference: if you got a frame, you must call
+// it again with pkt=NULL. pkt==NULL is treated differently from pkt.size==0
+// (pkt==NULL means get more output, pkt.size==0 is a flush/drain packet)
+static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)
+{
+ int ret;
+
+ *got_frame = 0;
+
+ if (pkt) {
+ ret = avcodec_send_packet(avctx, pkt);
+ // In particular, we don't expect AVERROR(EAGAIN), because we read all
+ // decoded frames with avcodec_receive_frame() until done.
+ if (ret < 0)
+ return ret == AVERROR_EOF ? 0 : ret;
+ }
+
+ ret = avcodec_receive_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ return ret;
+ if (ret >= 0)
+ *got_frame = 1;
+
+ return 0;
}
int guess_input_channel_layout(InputStream *ist)
return 0;
av_get_channel_layout_string(layout_name, sizeof(layout_name),
dec->channels, dec->channel_layout);
- av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
+ av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
"#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
}
return 1;
return AVERROR(ENOMEM);
decoded_frame = ist->decoded_frame;
- ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
+ ret = decode(avctx, decoded_frame, got_output, pkt);
if (!*got_output || ret < 0)
return ret;
the decoder could be delaying output by a packet or more. */
if (decoded_frame->pts != AV_NOPTS_VALUE)
ist->next_dts = decoded_frame->pts;
- else if (pkt->pts != AV_NOPTS_VALUE)
+ else if (pkt && pkt->pts != AV_NOPTS_VALUE) {
decoded_frame->pts = pkt->pts;
- pkt->pts = AV_NOPTS_VALUE;
+ }
resample_changed = ist->resample_sample_fmt != decoded_frame->format ||
ist->resample_channels != avctx->channels ||
return AVERROR(ENOMEM);
decoded_frame = ist->decoded_frame;
- ret = avcodec_decode_video2(ist->dec_ctx,
- decoded_frame, got_output, pkt);
+ ret = decode(ist->dec_ctx, decoded_frame, got_output, pkt);
if (!*got_output || ret < 0)
return ret;
decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
decoded_frame->pkt_dts);
- pkt->size = 0;
if (ist->st->sample_aspect_ratio.num)
decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{
int i;
- int got_output;
+ int repeating = 0;
AVPacket avpkt;
if (ist->next_dts == AV_NOPTS_VALUE)
av_init_packet(&avpkt);
avpkt.data = NULL;
avpkt.size = 0;
- goto handle_eof;
} else {
avpkt = *pkt;
}
- if (pkt->dts != AV_NOPTS_VALUE)
+ if (pkt && pkt->dts != AV_NOPTS_VALUE)
ist->next_dts = ist->last_dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
// while we have more to decode or while the decoder did output something on EOF
- while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
+ while (ist->decoding_needed && (!pkt || avpkt.size > 0)) {
int ret = 0;
- handle_eof:
+ int got_output = 0;
- ist->last_dts = ist->next_dts;
-
- if (avpkt.size && avpkt.size != pkt->size &&
- !(ist->dec->capabilities & AV_CODEC_CAP_SUBFRAMES)) {
- av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING,
- "Multiple frames in a packet from stream %d\n", pkt->stream_index);
- ist->showed_multi_packet_warning = 1;
- }
+ if (!repeating)
+ ist->last_dts = ist->next_dts;
switch (ist->dec_ctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- ret = decode_audio (ist, &avpkt, &got_output);
+ ret = decode_audio (ist, repeating ? NULL : &avpkt, &got_output);
break;
case AVMEDIA_TYPE_VIDEO:
- ret = decode_video (ist, &avpkt, &got_output);
- if (avpkt.duration)
- ist->next_dts += av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
+ ret = decode_video (ist, repeating ? NULL : &avpkt, &got_output);
+ if (repeating && !got_output)
+ ;
+ else if (pkt && pkt->duration)
+ ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
else if (ist->st->avg_frame_rate.num)
ist->next_dts += av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
AV_TIME_BASE_Q);
}
break;
case AVMEDIA_TYPE_SUBTITLE:
+ if (repeating)
+ break;
ret = transcode_subtitles(ist, &avpkt, &got_output);
break;
default:
break;
}
- // touch data and size only if not EOF
- if (pkt) {
- avpkt.data += ret;
- avpkt.size -= ret;
- }
- if (!got_output) {
- continue;
- }
+ if (!got_output)
+ break;
+
+ repeating = 1;
}
/* after flushing, send an EOF on all the filter inputs attached to the stream */
return NULL;
}
+static int init_output_bsfs(OutputStream *ost)
+{
+ AVBSFContext *ctx;
+ int i, ret;
+
+ if (!ost->nb_bitstream_filters)
+ return 0;
+
+ ost->bsf_ctx = av_mallocz_array(ost->nb_bitstream_filters, sizeof(*ost->bsf_ctx));
+ if (!ost->bsf_ctx)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < ost->nb_bitstream_filters; i++) {
+ ret = av_bsf_alloc(ost->bitstream_filters[i], &ctx);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating a bitstream filter context\n");
+ return ret;
+ }
+ ost->bsf_ctx[i] = ctx;
+
+ ret = avcodec_parameters_copy(ctx->par_in,
+ i ? ost->bsf_ctx[i - 1]->par_out : ost->st->codecpar);
+ if (ret < 0)
+ return ret;
+
+ ctx->time_base_in = i ? ost->bsf_ctx[i - 1]->time_base_out : ost->st->time_base;
+
+ ret = av_bsf_init(ctx);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n",
+ ost->bitstream_filters[i]->name);
+ return ret;
+ }
+ }
+
+ ctx = ost->bsf_ctx[ost->nb_bitstream_filters - 1];
+ ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out);
+ if (ret < 0)
+ return ret;
+
+ ost->st->time_base = ctx->time_base_out;
+
+ return 0;
+}
+
static int init_output_stream(OutputStream *ost, char *error, int error_len)
{
int ret = 0;
return ret;
}
+ /* initialize bitstream filters for the output stream
+ * needs to be done here, because the codec id for streamcopy is not
+ * known until now */
+ ret = init_output_bsfs(ost);
+ if (ret < 0)
+ return ret;
+
return ret;
}
}
}
+ av_buffer_unref(&hw_device_ctx);
+
/* finished ! */
ret = 0;