#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/libm.h"
+#include "libavutil/imgutils.h"
#include "libavformat/os_support.h"
#include "libswresample/swresample.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/buffersink.h"
+# include "libavfilter/buffersrc.h"
# include "libavfilter/vsrc_buffer.h"
#endif
static uint8_t *audio_out;
static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
-static void *samples;
static uint8_t *input_tmp= NULL;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
+typedef struct FrameBuffer {
+ uint8_t *base[4];
+ uint8_t *data[4];
+ int linesize[4];
+
+ int h, w;
+ enum PixelFormat pix_fmt;
+
+ int refcount;
+ struct InputStream *ist;
+ struct FrameBuffer *next;
+} FrameBuffer;
+
typedef struct InputStream {
int file_index;
AVStream *st;
int discard; /* true if stream data should be discarded */
int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
AVCodec *dec;
+ AVFrame *decoded_frame;
+ AVFrame *filtered_frame;
int64_t start; /* time when read started */
int64_t next_pts; /* synthetic pts for cases where pkt.pts
int is_start; /* is 1 at the start and after a discontinuity */
int showed_multi_packet_warning;
AVDictionary *opts;
+
+ /* a pool of free buffers for decoded data */
+ FrameBuffer *buffer_pool;
+ int dr1;
} InputStream;
typedef struct InputFile {
int nb_inter_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
+ SpecifierOpt *metadata_map;
+ int nb_metadata_map;
SpecifierOpt *presets;
int nb_presets;
SpecifierOpt *copy_initial_nonkeyframes;
init_opts();
}
+static int alloc_buffer(InputStream *ist, FrameBuffer **pbuf)
+{
+ AVCodecContext *s = ist->st->codec;
+ FrameBuffer *buf = av_mallocz(sizeof(*buf));
+ int ret, i;
+ const int pixel_size = av_pix_fmt_descriptors[s->pix_fmt].comp[0].step_minus1+1;
+ int h_chroma_shift, v_chroma_shift;
+ int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1
+ int w = s->width, h = s->height;
+
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
+ w += 2*edge;
+ h += 2*edge;
+ }
+
+ avcodec_align_dimensions(s, &w, &h);
+ if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
+ s->pix_fmt, 32)) < 0) {
+ av_freep(&buf);
+ return ret;
+ }
+ /* XXX this shouldn't be needed, but some tests break without this line
+ * those decoders are buggy and need to be fixed.
+ * the following tests fail:
+ * bethsoft-vid, cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit
+ */
+ memset(buf->base[0], 128, ret);
+
+ avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
+ for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
+ const int h_shift = i==0 ? 0 : h_chroma_shift;
+ const int v_shift = i==0 ? 0 : v_chroma_shift;
+ if (s->flags & CODEC_FLAG_EMU_EDGE)
+ buf->data[i] = buf->base[i];
+ else
+ buf->data[i] = buf->base[i] +
+ FFALIGN((buf->linesize[i]*edge >> v_shift) +
+ (pixel_size*edge >> h_shift), 32);
+ }
+ buf->w = s->width;
+ buf->h = s->height;
+ buf->pix_fmt = s->pix_fmt;
+ buf->ist = ist;
+
+ *pbuf = buf;
+ return 0;
+}
+
+static void free_buffer_pool(InputStream *ist)
+{
+ FrameBuffer *buf = ist->buffer_pool;
+ while (buf) {
+ ist->buffer_pool = buf->next;
+ av_freep(&buf->base[0]);
+ av_free(buf);
+ buf = ist->buffer_pool;
+ }
+}
+
+static void unref_buffer(InputStream *ist, FrameBuffer *buf)
+{
+ av_assert0(buf->refcount);
+ buf->refcount--;
+ if (!buf->refcount) {
+ buf->next = ist->buffer_pool;
+ ist->buffer_pool = buf;
+ }
+}
+
+static int codec_get_buffer(AVCodecContext *s, AVFrame *frame)
+{
+ InputStream *ist = s->opaque;
+ FrameBuffer *buf;
+ int ret, i;
+
+ if (!ist->buffer_pool && (ret = alloc_buffer(ist, &ist->buffer_pool)) < 0)
+ return ret;
+
+ buf = ist->buffer_pool;
+ ist->buffer_pool = buf->next;
+ buf->next = NULL;
+ if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
+ av_freep(&buf->base[0]);
+ av_free(buf);
+ ist->dr1 = 0;
+ if ((ret = alloc_buffer(ist, &buf)) < 0)
+ return ret;
+ }
+ buf->refcount++;
+
+ frame->opaque = buf;
+ frame->type = FF_BUFFER_TYPE_USER;
+ frame->extended_data = frame->data;
+ frame->pkt_pts = s->pkt ? s->pkt->pts : AV_NOPTS_VALUE;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
+ frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't
+ frame->data[i] = buf->data[i];
+ frame->linesize[i] = buf->linesize[i];
+ }
+
+ return 0;
+}
+
+static void codec_release_buffer(AVCodecContext *s, AVFrame *frame)
+{
+ InputStream *ist = s->opaque;
+ FrameBuffer *buf = frame->opaque;
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
+ frame->data[i] = NULL;
+
+ unref_buffer(ist, buf);
+}
+
+static void filter_release_buffer(AVFilterBuffer *fb)
+{
+ FrameBuffer *buf = fb->priv;
+ av_free(fb);
+ unref_buffer(buf->ist, buf);
+}
+
#if CONFIG_AVFILTER
static int configure_video_filters(InputStream *ist, OutputStream *ost)
received_sigterm = sig;
received_nb_signals++;
term_exit();
+ if(received_nb_signals > 3)
+ exit(123);
}
static void term_init(void)
av_dict_free(&output_files[i].opts);
}
for(i=0;i<nb_input_files;i++) {
- av_close_input_file(input_files[i].ctx);
+ avformat_close_input(&input_files[i].ctx);
}
- for (i = 0; i < nb_input_streams; i++)
+ for (i = 0; i < nb_input_streams; i++) {
+ av_freep(&input_streams[i].decoded_frame);
+ av_freep(&input_streams[i].filtered_frame);
av_dict_free(&input_streams[i].opts);
+ free_buffer_pool(&input_streams[i]);
+ }
if (vstats_file)
fclose(vstats_file);
av_free(audio_buf);
av_free(audio_out);
allocated_audio_buf_size= allocated_audio_out_size= 0;
- av_free(samples);
#if CONFIG_AVFILTER
avfilter_uninit();
memset(buf, fill_char, size);
}
-static void do_audio_out(AVFormatContext *s,
- OutputStream *ost,
- InputStream *ist,
- unsigned char *buf, int size)
+static void do_audio_out(AVFormatContext *s, OutputStream *ost,
+ InputStream *ist, AVFrame *decoded_frame)
{
uint8_t *buftmp;
int64_t audio_out_size, audio_buf_size;
- int64_t allocated_for_size= size;
int size_out, frame_bytes, ret, resample_changed;
AVCodecContext *enc= ost->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
const int coded_bps = av_get_bits_per_sample(enc->codec->id);
+ uint8_t *buf = decoded_frame->data[0];
+ int size = decoded_frame->nb_samples * dec->channels * isize;
+ int64_t allocated_for_size = size;
need_realloc:
audio_buf_size= (allocated_for_size + isize*dec->channels - 1) / (isize*dec->channels);
static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
{
- static unsigned int samples_size = 0;
+ AVFrame *decoded_frame;
+ AVCodecContext *avctx = ist->st->codec;
int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt);
- uint8_t *decoded_data_buf = NULL;
- int decoded_data_size = 0;
int i, ret;
- if (pkt && samples_size < FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE)) {
- av_free(samples);
- samples_size = FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE);
- samples = av_malloc(samples_size);
- }
- decoded_data_size = samples_size;
+ if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
+ return AVERROR(ENOMEM);
+ else
+ avcodec_get_frame_defaults(ist->decoded_frame);
+ decoded_frame = ist->decoded_frame;
- ret = avcodec_decode_audio3(ist->st->codec, samples, &decoded_data_size,
- pkt);
- if (ret < 0)
+ ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
+ if (ret < 0) {
return ret;
- *got_output = decoded_data_size > 0;
+ }
- /* Some bug in mpeg audio decoder gives */
- /* decoded_data_size < 0, it seems they are overflows */
if (!*got_output) {
/* no audio frame */
return ret;
}
- decoded_data_buf = (uint8_t *)samples;
- ist->next_pts += ((int64_t)AV_TIME_BASE/bps * decoded_data_size) /
- (ist->st->codec->sample_rate * ist->st->codec->channels);
+ /* if the decoder provides a pts, use it instead of the last packet pts.
+ the decoder could be delaying output by a packet or more. */
+ if (decoded_frame->pts != AV_NOPTS_VALUE)
+ ist->next_pts = decoded_frame->pts;
+
+ /* increment next_pts to use for the case where the input stream does not
+ have timestamps or there are multiple frames in the packet */
+ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
+ avctx->sample_rate;
// preprocess audio (volume)
if (audio_volume != 256) {
- switch (ist->st->codec->sample_fmt) {
+ int decoded_data_size = decoded_frame->nb_samples * avctx->channels * bps;
+ void *samples = decoded_frame->data[0];
+ switch (avctx->sample_fmt) {
case AV_SAMPLE_FMT_U8:
{
uint8_t *volp = samples;
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
- do_audio_out(output_files[ost->file_index].ctx, ost, ist,
- decoded_data_buf, decoded_data_size);
+ do_audio_out(output_files[ost->file_index].ctx, ost, ist, decoded_frame);
}
+
return ret;
}
int64_t *best_effort_timestamp;
AVRational *frame_sample_aspect;
- if (!(decoded_frame = avcodec_alloc_frame()))
+ if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
+ else
+ avcodec_get_frame_defaults(ist->decoded_frame);
+ decoded_frame = ist->decoded_frame;
pkt->pts = *pkt_pts;
pkt->dts = *pkt_dts;
*pkt_pts = AV_NOPTS_VALUE;
ret = avcodec_decode_video2(ist->st->codec,
decoded_frame, got_output, pkt);
if (ret < 0)
- goto fail;
+ return ret;
quality = same_quant ? decoded_frame->quality : 0;
if (!*got_output) {
/* no picture yet */
- av_freep(&decoded_frame);
return ret;
}
if (!frame_sample_aspect->num)
*frame_sample_aspect = ist->st->sample_aspect_ratio;
decoded_frame->pts = ist->pts;
-
- av_vsrc_buffer_add_frame(ost->input_video_filter, decoded_frame, AV_VSRC_BUF_FLAG_OVERWRITE);
+ if (ist->dr1) {
+ FrameBuffer *buf = decoded_frame->opaque;
+ AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
+ decoded_frame->data, decoded_frame->linesize,
+ AV_PERM_READ | AV_PERM_PRESERVE,
+ ist->st->codec->width, ist->st->codec->height,
+ ist->st->codec->pix_fmt);
+
+ avfilter_copy_frame_props(fb, decoded_frame);
+ fb->pts = ist->pts;
+ fb->buf->priv = buf;
+ fb->buf->free = filter_release_buffer;
+
+ buf->refcount++;
+ av_buffersrc_buffer(ost->input_video_filter, fb);
+ } else
+ if((av_vsrc_buffer_add_frame(ost->input_video_filter, decoded_frame, AV_VSRC_BUF_FLAG_OVERWRITE)) < 0){
+ av_log(0, AV_LOG_FATAL, "Failed to inject frame into filter network\n");
+ exit_program(1);
+ }
}
}
#endif
#if CONFIG_AVFILTER
if (ost->input_video_filter) {
- frame_available = avfilter_poll_frame(ost->output_video_filter->inputs[0]);
+ frame_available = av_buffersink_poll_frame(ost->output_video_filter);
}
while (frame_available) {
if (ost->output_video_filter) {
AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
- if (av_buffersink_get_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0)
+ if (av_buffersink_get_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0){
+ av_log(0, AV_LOG_WARNING, "AV Filter told us it has a frame available but failed to output one\n");
goto cont;
- if (!filtered_frame && !(filtered_frame = avcodec_alloc_frame())) {
- ret = AVERROR(ENOMEM);
- goto fail;
}
+ if (!ist->filtered_frame && !(ist->filtered_frame = avcodec_alloc_frame())) {
+ av_free(buffer_to_free);
+ return AVERROR(ENOMEM);
+ } else
+ avcodec_get_frame_defaults(ist->filtered_frame);
+ filtered_frame = ist->filtered_frame;
*filtered_frame= *decoded_frame; //for me_threshold
if (ost->picref) {
avfilter_fill_frame_from_video_buffer_ref(filtered_frame, ost->picref);
do_video_stats(output_files[ost->file_index].ctx, ost, frame_size);
#if CONFIG_AVFILTER
cont:
- frame_available = ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
+ frame_available = ost->output_video_filter && av_buffersink_poll_frame(ost->output_video_filter);
avfilter_unref_buffer(ost->picref);
}
- av_freep(&filtered_frame);
#endif
}
-fail:
av_free(buffer_to_free);
- av_freep(&decoded_frame);
return ret;
}
if (ret < 0)
return ret;
+
+ avpkt.dts=
+ avpkt.pts= AV_NOPTS_VALUE;
+
// touch data and size only if not EOF
if (pkt) {
if(ist->st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
avcodec_get_name(ist->st->codec->codec_id), ist->file_index, ist->st->index);
return AVERROR(EINVAL);
}
+
+ ist->dr1 = codec->capabilities & CODEC_CAP_DR1;
+ if (codec->type == AVMEDIA_TYPE_VIDEO && ist->dr1) {
+ ist->st->codec->get_buffer = codec_get_buffer;
+ ist->st->codec->release_buffer = codec_release_buffer;
+ ist->st->codec->opaque = ist;
+ }
+
if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
snprintf(error, error_len, "Error while opening decoder for input stream #%d:%d",
ist->file_index, ist->st->index);
codec->bit_rate = icodec->bit_rate;
codec->rc_max_rate = icodec->rc_max_rate;
codec->rc_buffer_size = icodec->rc_buffer_size;
+ codec->field_order = icodec->field_order;
codec->extradata = av_mallocz(extra_size);
if (!codec->extradata) {
return AVERROR(ENOMEM);
return 0;
}
-static void parse_meta_type(char *arg, char *type, int *index)
+/**
+ * Parse a metadata specifier in arg.
+ * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
+ * @param index for type c/p, chapter/program index is written here
+ * @param stream_spec for type s, the stream specifier is written here
+ */
+static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
{
if (*arg) {
*type = *arg;
case 'g':
break;
case 's':
+ if (*(++arg) && *arg != ':') {
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
+ exit_program(1);
+ }
+ *stream_spec = *arg == ':' ? arg + 1 : "";
+ break;
case 'c':
case 'p':
if (*(++arg) == ':')
*type = 'g';
}
-static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg)
+static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
{
- MetadataMap *m, *m1;
- char *p;
-
- o->meta_data_maps = grow_array(o->meta_data_maps, sizeof(*o->meta_data_maps),
- &o->nb_meta_data_maps, o->nb_meta_data_maps + 1);
+ AVDictionary **meta_in = NULL;
+ AVDictionary **meta_out;
+ int i, ret = 0;
+ char type_in, type_out;
+ const char *istream_spec = NULL, *ostream_spec = NULL;
+ int idx_in = 0, idx_out = 0;
- m = &o->meta_data_maps[o->nb_meta_data_maps - 1][1];
- m->file = strtol(arg, &p, 0);
- parse_meta_type(*p ? p + 1 : p, &m->type, &m->index);
+ parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
+ parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
- m1 = &o->meta_data_maps[o->nb_meta_data_maps - 1][0];
- if (p = strchr(opt, ':'))
- parse_meta_type(p + 1, &m1->type, &m1->index);
- else
- m1->type = 'g';
-
- if (m->type == 'g' || m1->type == 'g')
+ if (type_in == 'g' || type_out == 'g')
o->metadata_global_manual = 1;
- if (m->type == 's' || m1->type == 's')
+ if (type_in == 's' || type_out == 's')
o->metadata_streams_manual = 1;
- if (m->type == 'c' || m1->type == 'c')
+ if (type_in == 'c' || type_out == 'c')
o->metadata_chapters_manual = 1;
- return 0;
-}
+#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
+ if ((index) < 0 || (index) >= (nb_elems)) {\
+ av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
+ (desc), (index));\
+ exit_program(1);\
+ }
+
+#define SET_DICT(type, meta, context, index)\
+ switch (type) {\
+ case 'g':\
+ meta = &context->metadata;\
+ break;\
+ case 'c':\
+ METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
+ meta = &context->chapters[index]->metadata;\
+ break;\
+ case 'p':\
+ METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
+ meta = &context->programs[index]->metadata;\
+ break;\
+ }\
+
+ SET_DICT(type_in, meta_in, ic, idx_in);
+ SET_DICT(type_out, meta_out, oc, idx_out);
+
+ /* for input streams choose first matching stream */
+ if (type_in == 's') {
+ for (i = 0; i < ic->nb_streams; i++) {
+ if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
+ meta_in = &ic->streams[i]->metadata;
+ break;
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ if (!meta_in) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
+ exit_program(1);
+ }
+ }
-static int opt_map_meta_data(OptionsContext *o, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_WARNING, "-map_meta_data is deprecated and will be removed soon. "
- "Use -map_metadata instead.\n");
- return opt_map_metadata(o, opt, arg);
+ if (type_out == 's') {
+ for (i = 0; i < oc->nb_streams; i++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
+ meta_out = &oc->streams[i]->metadata;
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ } else
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+
+ return 0;
}
static int opt_recording_timestamp(OptionsContext *o, const char *opt, const char *arg)
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
term_exit();
+ signal(SIGINT, SIG_DFL);
if (!read_yesno()) {
av_log(0, AV_LOG_FATAL, "Not overwriting - exiting\n");
exit_program(1);
ic->interrupt_callback = int_cb;
if (loop_input) {
- av_log(NULL, AV_LOG_WARNING, "-loop_input is deprecated, use -loop 1\n");
+ av_log(NULL, AV_LOG_WARNING,
+ "-loop_input is deprecated, use -loop 1\n"
+ "Note, both loop options only work with -f image2\n"
+ );
ic->loop_input = loop_input;
}
- /* open the input file with generic libav function */
+ /* open the input file with generic avformat function */
err = avformat_open_input(&ic, filename, file_iformat, &format_opts);
if (err < 0) {
print_error(filename, err);
ret = avformat_find_stream_info(ic, opts);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
- av_close_input_file(ic);
+ avformat_close_input(&ic);
exit_program(1);
}
ost = new_output_stream(o, s, codec->type);
st = ost->st;
avctx = st->codec;
+ ost->enc = codec;
// FIXME: a more elegant solution is needed
memcpy(st, ic->streams[i], sizeof(AVStream));
}
if (!(oc->oformat->flags & AVFMT_NOFILE)) {
- /* test if it already exists to avoid loosing precious files */
+ /* test if it already exists to avoid losing precious files */
assert_file_overwrite(filename);
/* open the file */
oc->loop_output = loop_output;
}
+ /* copy metadata */
+ for (i = 0; i < o->nb_metadata_map; i++) {
+ char *p;
+ int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+
+ if (in_file_index < 0)
+ continue;
+ if (in_file_index >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
+ exit_program(1);
+ }
+ copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index].ctx, o);
+ }
+
/* copy chapters */
if (o->chapters_input_file >= nb_input_files) {
if (o->chapters_input_file == INT_MAX) {
copy_chapters(&input_files[o->chapters_input_file], &output_files[nb_output_files - 1],
!o->metadata_chapters_manual);
- /* copy metadata */
- for (i = 0; i < o->nb_meta_data_maps; i++) {
- AVFormatContext *files[2];
- AVDictionary **meta[2];
- int j;
-
-#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
- if ((index) < 0 || (index) >= (nb_elems)) {\
- av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps\n",\
- (desc), (index));\
- exit_program(1);\
- }
-
- int in_file_index = o->meta_data_maps[i][1].file;
- if (in_file_index < 0)
- continue;
- METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file")
-
- files[0] = oc;
- files[1] = input_files[in_file_index].ctx;
-
- for (j = 0; j < 2; j++) {
- MetadataMap *map = &o->meta_data_maps[i][j];
-
- switch (map->type) {
- case 'g':
- meta[j] = &files[j]->metadata;
- break;
- case 's':
- METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream")
- meta[j] = &files[j]->streams[map->index]->metadata;
- break;
- case 'c':
- METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter")
- meta[j] = &files[j]->chapters[map->index]->metadata;
- break;
- case 'p':
- METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
- meta[j] = &files[j]->programs[map->index]->metadata;
- break;
- default:
- abort();
- }
- }
-
- av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE);
- }
-
/* copy global metadata by default */
if (!o->metadata_global_manual && nb_input_files){
av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
for (i = 0; i < o->nb_metadata; i++) {
AVDictionary **m;
char type, *val;
- int index = 0;
+ const char *stream_spec;
+ int index = 0, j, ret;
val = strchr(o->metadata[i].u.str, '=');
if (!val) {
}
*val++ = 0;
- parse_meta_type(o->metadata[i].specifier, &type, &index);
- switch (type) {
- case 'g':
- m = &oc->metadata;
- break;
- case 's':
- if (index < 0 || index >= oc->nb_streams) {
- av_log(NULL, AV_LOG_FATAL, "Invalid stream index %d in metadata specifier.\n", index);
- exit_program(1);
+ parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
+ if (type == 's') {
+ for (j = 0; j < oc->nb_streams; j++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
+ av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
+ } else if (ret < 0)
+ exit_program(1);
}
- m = &oc->streams[index]->metadata;
- break;
- case 'c':
- if (index < 0 || index >= oc->nb_chapters) {
- av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+ printf("ret %d, stream_spec %s\n", ret, stream_spec);
+ }
+ else {
+ switch (type) {
+ case 'g':
+ m = &oc->metadata;
+ break;
+ case 'c':
+ if (index < 0 || index >= oc->nb_chapters) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+ exit_program(1);
+ }
+ m = &oc->chapters[index]->metadata;
+ break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
exit_program(1);
}
- m = &oc->chapters[index]->metadata;
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
- exit_program(1);
+ av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
}
-
- av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
}
reset_options(o, 0);
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
{ "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
{ "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" },
- { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
+ { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
{ "map_channel", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_channel}, "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
- { "map_meta_data", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
- "outfile[,metadata]:infile[,metadata]" },
- { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",
+ { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata_map)}, "set metadata information of outfile from infile",
"outfile[,metadata]:infile[,metadata]" },
{ "map_chapters", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(chapters_input_file)}, "set chapters mapping", "input_file_index" },
{ "t", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(recording_time)}, "record or transcode \"duration\" seconds of audio/video", "duration" },
av_register_all();
avformat_network_init();
- show_banner();
+ show_banner(argc, argv, options);
term_init();