Newer
Older
}
ost->logfile = f;
}
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
AVCodec *codec = ost->enc;
AVCodecContext *dec = NULL;
if ((ist = get_input_stream(ost)))
dec = ist->st->codec;
if (dec && dec->subtitle_header) {
ost->st->codec->subtitle_header = av_malloc(dec->subtitle_header_size);
if (!ost->st->codec->subtitle_header) {
ret = AVERROR(ENOMEM);
goto dump_format;
}
memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
ost->st->codec->subtitle_header_size = dec->subtitle_header_size;
}
Michael Niedermayer
committed
if (!av_dict_get(ost->opts, "threads", NULL, 0))
av_dict_set(&ost->opts, "threads", "auto", 0);
if (avcodec_open2(ost->st->codec, codec, &ost->opts) < 0) {
snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height",
ret = AVERROR(EINVAL);
goto dump_format;
assert_codec_experimental(ost->st->codec, 1);
assert_avoptions(ost->opts);
if (ost->st->codec->bit_rate && ost->st->codec->bit_rate < 1000)
av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low."
" It takes bits/s as argument, not kbits/s\n");
Michael Niedermayer
committed
extra_size += ost->st->codec->extradata_size;
if (ost->st->codec->me_threshold)
input_streams[ost->source_index]->st->codec->debug |= FF_DEBUG_MV;
/* init input streams */
for (i = 0; i < nb_input_streams; i++)
if ((ret = init_input_stream(i, error, sizeof(error))) < 0)
/* discard unused programs */
for (i = 0; i < nb_input_files; i++) {
InputFile *ifile = input_files[i];
for (j = 0; j < ifile->ctx->nb_programs; j++) {
AVProgram *p = ifile->ctx->programs[j];
int discard = AVDISCARD_ALL;
for (k = 0; k < p->nb_stream_indexes; k++)
if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) {
discard = AVDISCARD_DEFAULT;
break;
}
p->discard = discard;
Anton Khirnov
committed
for (i = 0; i < nb_output_files; i++) {
oc = output_files[i]->ctx;
oc->interrupt_callback = int_cb;
if ((ret = avformat_write_header(oc, &output_files[i]->opts)) < 0) {
char errbuf[128];
const char *errbuf_ptr = errbuf;
if (av_strerror(ret, errbuf, sizeof(errbuf)) < 0)
errbuf_ptr = strerror(AVUNERROR(ret));
snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?): %s", i, errbuf_ptr);
ret = AVERROR(EINVAL);
goto dump_format;
}
// assert_avoptions(output_files[i]->opts);
if (strcmp(oc->oformat->name, "rtp")) {
want_sdp = 0;
}
}
dump_format:
/* dump the file output parameters - cannot be done before in case
of stream copy */
for (i = 0; i < nb_output_files; i++) {
av_dump_format(output_files[i]->ctx, i, output_files[i]->ctx->filename, 1);
}
/* dump the stream mapping */
av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
for (j = 0; j < ist->nb_filters; j++) {
if (ist->filters[j]->graph->graph_desc) {
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s",
ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
ist->filters[j]->name);
if (nb_filtergraphs > 1)
av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index);
av_log(NULL, AV_LOG_INFO, "\n");
}
}
}
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->attachment_filename) {
/* an attached file */
av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
ost->attachment_filename, ost->file_index, ost->index);
continue;
if (ost->filter && ost->filter->graph->graph_desc) {
/* output from a complex graph */
av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name);
if (nb_filtergraphs > 1)
av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file_index,
ost->index, ost->enc ? ost->enc->name : "?");
continue;
}
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d -> #%d:%d",
input_streams[ost->source_index]->file_index,
input_streams[ost->source_index]->st->index,
ost->file_index,
ost->index);
if (ost->sync_ist != input_streams[ost->source_index])
av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",
ost->sync_ist->file_index,
ost->sync_ist->st->index);
if (ost->stream_copy)
av_log(NULL, AV_LOG_INFO, " (copy)");
else
av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index]->dec ?
input_streams[ost->source_index]->dec->name : "?",
ost->enc ? ost->enc->name : "?");
av_log(NULL, AV_LOG_INFO, "\n");
}
if (ret) {
av_log(NULL, AV_LOG_ERROR, "%s\n", error);
return ret;
}
if (want_sdp) {
print_sdp();
return 0;
}
/**
* @return 1 if there are still streams where more output is wanted,
* 0 otherwise
*/
static int need_output(void)
{
int i;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
AVFormatContext *os = output_files[ost->file_index]->ctx;
if (ost->is_past_recording_time ||
(os->pb && avio_tell(os->pb) >= of->limit_filesize))
continue;
if (ost->frame_number >= ost->max_frames) {
int j;
for (j = 0; j < of->ctx->nb_streams; j++)
output_streams[of->ost_index + j]->is_past_recording_time = 1;
continue;
}
return 1;
}
return 0;
}
static int select_input_file(uint8_t *no_packet)
{
int64_t ipts_min = INT64_MAX;
int i, file_index = -1;
for (i = 0; i < nb_input_streams; i++) {
InputStream *ist = input_streams[i];
int64_t ipts = ist->pts;
if (ist->discard || no_packet[ist->file_index])
continue;
if (!input_files[ist->file_index]->eof_reached) {
if (ipts < ipts_min) {
ipts_min = ipts;
file_index = ist->file_index;
}
}
}
return file_index;
}
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
static int check_keyboard_interaction(int64_t cur_time)
{
int i, ret, key;
static int64_t last_time;
if (received_nb_signals)
return AVERROR_EXIT;
/* read_key() returns 0 on EOF */
if(cur_time - last_time >= 100000 && !run_as_daemon){
key = read_key();
last_time = cur_time;
}else
key = -1;
if (key == 'q')
return AVERROR_EXIT;
if (key == '+') av_log_set_level(av_log_get_level()+10);
if (key == '-') av_log_set_level(av_log_get_level()-10);
if (key == 's') qp_hist ^= 1;
if (key == 'h'){
if (do_hex_dump){
do_hex_dump = do_pkt_dump = 0;
} else if(do_pkt_dump){
do_hex_dump = 1;
} else
do_pkt_dump = 1;
av_log_set_level(AV_LOG_DEBUG);
}
if (key == 'c' || key == 'C'){
char buf[4096], target[64], command[256], arg[256] = {0};
double time;
int k, n = 0;
fprintf(stderr, "\nEnter command: <target> <time> <command>[ <argument>]\n");
i = 0;
while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
if (k > 0)
buf[i++] = k;
buf[i] = 0;
if (k > 0 &&
(n = sscanf(buf, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &time, command, arg)) >= 3) {
av_log(NULL, AV_LOG_DEBUG, "Processing command target:%s time:%f command:%s arg:%s",
target, time, command, arg);
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
if (fg->graph) {
if (time < 0) {
ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),
key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);
fprintf(stderr, "Command reply for stream %d: ret:%d res:%s\n", i, ret, buf);
} else {
ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
}
}
}
} else {
av_log(NULL, AV_LOG_ERROR,
"Parse error, at least 3 arguments were expected, "
"only %d given in string '%s'\n", n, buf);
}
}
if (key == 'd' || key == 'D'){
int debug=0;
if(key == 'D') {
debug = input_streams[0]->st->codec->debug<<1;
if(!debug) debug = 1;
while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash
debug += debug;
}else
if(scanf("%d", &debug)!=1)
fprintf(stderr,"error parsing debug value\n");
for(i=0;i<nb_input_streams;i++) {
input_streams[i]->st->codec->debug = debug;
}
for(i=0;i<nb_output_streams;i++) {
OutputStream *ost = output_streams[i];
ost->st->codec->debug = debug;
}
if(debug) av_log_set_level(AV_LOG_DEBUG);
fprintf(stderr,"debug=%d\n", debug);
}
if (key == '?'){
fprintf(stderr, "key function\n"
"? show this help\n"
"+ increase verbosity\n"
"- decrease verbosity\n"
"c Send command to filtergraph\n"
"D cycle through available debug modes\n"
"h dump packets/hex press to cycle through the 3 states\n"
"q quit\n"
"s Show QP histogram\n"
);
}
return 0;
}
/*
* The following code is the main loop of the file converter
*/
static int transcode(void)
{
int ret, i;
AVFormatContext *is, *os;
OutputStream *ost;
InputStream *ist;
uint8_t *no_packet;
int no_packet_count = 0;
int64_t timer_start;
if (!(no_packet = av_mallocz(nb_input_files)))
exit_program(1);
ret = transcode_init();
if (ret < 0)
goto fail;
av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
Leon van Stuivenberg
committed
}
timer_start = av_gettime();
for (; received_sigterm == 0;) {
int file_index, ist_index;
Michael Niedermayer
committed
int64_t cur_time= av_gettime();
/* if 'q' pressed, exits */
if (!using_stdin)
if (check_keyboard_interaction(cur_time) < 0)
break;
/* check if there's any stream where output is still needed */
if (!need_output()) {
av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
/* select the stream that we must read now */
file_index = select_input_file(no_packet);
if (file_index < 0) {
if (no_packet_count) {
no_packet_count = 0;
memset(no_packet, 0, nb_input_files);
usleep(10000);
continue;
}
Fabrice Bellard
committed
}
/* read a frame from it and output it in the fifo */
is = input_files[file_index]->ctx;
ret = av_read_frame(is, &pkt);
if (ret == AVERROR(EAGAIN)) {
no_packet[file_index] = 1;
no_packet_count++;
input_files[file_index]->eof_reached = 1;
for (i = 0; i < input_files[file_index]->nb_streams; i++) {
ist = input_streams[input_files[file_index]->ist_index + i];
if (ist->decoding_needed)
output_packet(ist, NULL);
}
if (opt_shortest)
break;
else
continue;
memset(no_packet, 0, nb_input_files);
if (do_pkt_dump) {
av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
is->streams[pkt.stream_index]);
Fabrice Bellard
committed
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
if (pkt.stream_index >= input_files[file_index]->nb_streams)
ist_index = input_files[file_index]->ist_index + pkt.stream_index;
ist = input_streams[ist_index];
if (ist->discard)
goto discard_packet;
Michael Niedermayer
committed
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
Michael Niedermayer
committed
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
Michael Niedermayer
committed
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts *= ist->ts_scale;
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts *= ist->ts_scale;
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
"next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n",
ist_index, av_get_media_type_string(ist->st->codec->codec_type),
av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &ist->st->time_base),
av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &ist->st->time_base),
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
input_files[ist->file_index]->ts_offset);
if (pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && !copy_ts) {
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
int64_t delta = pkt_dts - ist->next_dts;
if (is->iformat->flags & AVFMT_TS_DISCONT) {
if(delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
(delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&
ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
pkt_dts+1<ist->pts){
input_files[ist->file_index]->ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
delta, input_files[ist->file_index]->ts_offset);
Michael Niedermayer
committed
pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
Michael Niedermayer
committed
pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
} else {
if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
(delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
pkt_dts+1<ist->pts){
av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);
pkt.dts = AV_NOPTS_VALUE;
}
if (pkt.pts != AV_NOPTS_VALUE){
int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
delta = pkt_pts - ist->next_dts;
if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
(delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
pkt_pts+1<ist->pts) {
av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);
pkt.pts = AV_NOPTS_VALUE;
}
}
}
// fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
if ((ret = output_packet(ist, &pkt)) < 0 ||
((ret = poll_filters()) < 0 && ret != AVERROR_EOF)) {
char buf[128];
av_strerror(ret, buf, sizeof(buf));
av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
ist->file_index, ist->st->index, buf);
if (exit_on_error)
Fabrice Bellard
committed
av_free_packet(&pkt);
Fabrice Bellard
committed
Fabrice Bellard
committed
/* dump report by using the output first video and audio streams */
print_report(0, timer_start, cur_time);
Fabrice Bellard
committed
/* at the end of stream, we must flush the decoder buffers */
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
output_packet(ist, NULL);
Fabrice Bellard
committed
}
}
flush_encoders();
Fabrice Bellard
committed
term_exit();
Michael Niedermayer
committed
/* write the trailer if needed and close file */
for (i = 0; i < nb_output_files; i++) {
os = output_files[i]->ctx;
Michael Niedermayer
committed
av_write_trailer(os);
}
/* dump report by using the first video and audio streams */
print_report(1, timer_start, av_gettime());
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
Michael Niedermayer
committed
av_freep(&ost->st->codec->stats_in);
avcodec_close(ost->st->codec);
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
Michael Niedermayer
committed
avcodec_close(ist->st->codec);
fail:
av_freep(&no_packet);
if (output_streams) {
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->stream_copy)
av_freep(&ost->st->codec->extradata);
if (ost->logfile) {
fclose(ost->logfile);
ost->logfile = NULL;
}
av_freep(&ost->st->codec->subtitle_header);
av_free(ost->forced_kf_pts);
av_dict_free(&ost->opts);
static int opt_frame_crop(const char *opt, const char *arg)
Michael Niedermayer
committed
{
av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the crop filter instead\n", opt);
Michael Niedermayer
committed
}
static int opt_pad(const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the pad filter instead\n", opt);
Todd Kirby
committed
}
static int opt_video_channel(const char *opt, const char *arg)
Fabrice Bellard
committed
{
av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
return opt_default("channel", arg);
Fabrice Bellard
committed
}
static int opt_video_standard(const char *opt, const char *arg)
av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
return opt_default("standard", arg);
static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg)
audio_codec_name = arg;
return parse_option(o, "codec:a", arg, options);
static int opt_video_codec(OptionsContext *o, const char *opt, const char *arg)
video_codec_name = arg;
return parse_option(o, "codec:v", arg, options);
static int opt_subtitle_codec(OptionsContext *o, const char *opt, const char *arg)
subtitle_codec_name = arg;
return parse_option(o, "codec:s", arg, options);
static int opt_data_codec(OptionsContext *o, const char *opt, const char *arg)
return parse_option(o, "codec:d", arg, options);
static int opt_map(OptionsContext *o, const char *opt, const char *arg)
StreamMap *m = NULL;
int i, negative = 0, file_idx;
int sync_file_idx = -1, sync_stream_idx = 0;
if (*arg == '-') {
negative = 1;
arg++;
}
map = av_strdup(arg);
/* parse sync stream first, just pick first matching stream */
if (sync = strchr(map, ',')) {
*sync = 0;
sync_file_idx = strtol(sync + 1, &sync, 0);
if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
exit_program(1);
}
if (*sync)
sync++;
for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
if (check_stream_specifier(input_files[sync_file_idx]->ctx,
input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
sync_stream_idx = i;
break;
}
if (i == input_files[sync_file_idx]->nb_streams) {
av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
"match any streams.\n", arg);
exit_program(1);
}
}
if (map[0] == '[') {
/* this mapping refers to lavfi output */
const char *c = map + 1;
o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
&o->nb_stream_maps, o->nb_stream_maps + 1);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->linklabel = av_get_token(&c, "]");
if (!m->linklabel) {
av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
exit_program(1);
}
} else {
file_idx = strtol(map, &p, 0);
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
exit_program(1);
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
if (negative)
/* disable some already defined maps */
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
if (file_idx == m->file_index &&
check_stream_specifier(input_files[m->file_index]->ctx,
input_files[m->file_index]->ctx->streams[m->stream_index],
*p == ':' ? p + 1 : p) > 0)
m->disabled = 1;
}
else
for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
*p == ':' ? p + 1 : p) <= 0)
continue;
o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
&o->nb_stream_maps, o->nb_stream_maps + 1);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->file_index = file_idx;
m->stream_index = i;
if (sync_file_idx >= 0) {
m->sync_file_index = sync_file_idx;
m->sync_stream_index = sync_stream_idx;
} else {
m->sync_file_index = file_idx;
m->sync_stream_index = i;
}
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
exit_program(1);
}
av_freep(&map);
static int opt_attach(OptionsContext *o, const char *opt, const char *arg)
o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
&o->nb_attachments, o->nb_attachments + 1);
o->attachments[o->nb_attachments - 1] = arg;
return 0;
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
static int opt_map_channel(OptionsContext *o, const char *opt, const char *arg)
{
int n;
AVStream *st;
AudioChannelMap *m;
o->audio_channel_maps =
grow_array(o->audio_channel_maps, sizeof(*o->audio_channel_maps),
&o->nb_audio_channel_maps, o->nb_audio_channel_maps + 1);
m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
/* muted channel syntax */
n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
if ((n == 1 || n == 3) && m->channel_idx == -1) {
m->file_idx = m->stream_idx = -1;
if (n == 1)
m->ofile_idx = m->ostream_idx = -1;
return 0;
}
/* normal syntax */
n = sscanf(arg, "%d.%d.%d:%d.%d",
&m->file_idx, &m->stream_idx, &m->channel_idx,
&m->ofile_idx, &m->ostream_idx);
if (n != 3 && n != 5) {
av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
"[file.stream.channel|-1][:syncfile:syncstream]\n");
exit_program(1);
}
if (n != 5) // only file.stream.channel specified
m->ofile_idx = m->ostream_idx = -1;
/* check input */
if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
m->file_idx);
exit_program(1);
}
if (m->stream_idx < 0 ||
m->stream_idx >= input_files[m->file_idx]->nb_streams) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
m->file_idx, m->stream_idx);
exit_program(1);
}
st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
m->file_idx, m->stream_idx);
exit_program(1);
}
if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
m->file_idx, m->stream_idx, m->channel_idx);
exit_program(1);
}
return 0;
}
/**
* 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;
switch (*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) == ':')
*index = strtol(++arg, NULL, 0);
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
}
} else
*type = 'g';
}
static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
Patrice Bensoussan
committed
{
AVDictionary **meta_in = NULL;
AVDictionary **meta_out = NULL;
int i, ret = 0;
char type_in, type_out;
const char *istream_spec = NULL, *ostream_spec = NULL;
int idx_in = 0, idx_out = 0;
Patrice Bensoussan
committed
parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
Anton Khirnov
committed
if (!ic) {
if (type_out == 'g' || !*outspec)
o->metadata_global_manual = 1;
if (type_out == 's' || !*outspec)
o->metadata_streams_manual = 1;
if (type_out == 'c' || !*outspec)
o->metadata_chapters_manual = 1;
return 0;
}
if (type_in == 'g' || type_out == 'g')
o->metadata_global_manual = 1;
if (type_in == 's' || type_out == 's')
o->metadata_streams_manual = 1;
if (type_in == 'c' || type_out == 'c')
o->metadata_chapters_manual = 1;
#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);\
}
Patrice Bensoussan
committed
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
#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);
}
}
Patrice Bensoussan
committed
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);
static int opt_recording_timestamp(OptionsContext *o, const char *opt, const char *arg)
{
char buf[128];
int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
struct tm time = *gmtime((time_t*)&recording_timestamp);
strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
parse_option(o, "metadata", buf, options);
av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
"tag instead.\n", opt);
return 0;
}
static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
codec = encoder ?
avcodec_find_encoder_by_name(name) :
avcodec_find_decoder_by_name(name);
av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
if (codec->type != type) {
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
if (codec_name) {
AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
st->codec->codec_id = codec->id;
return codec;
} else
return avcodec_find_decoder(st->codec->codec_id);
/**
* Add all the streams from the given input file to the global
* list of input streams.
*/
static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
char *next, *codec_tag = NULL;
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist = av_mallocz(sizeof(*ist));
if (!ist)
exit_program(1);
input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
input_streams[nb_input_streams - 1] = ist;
ist->st = st;
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
ist->opts = filter_codec_opts(codec_opts, choose_decoder(o, ic, st), ic, st);
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next)
tag = AV_RL32(codec_tag);
st->codec->codec_tag = tag;
}
ist->dec = choose_decoder(o, ic, st);
switch (dec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
if (dec->lowres) {
dec->flags |= CODEC_FLAG_EMU_EDGE;
}
ist->resample_height = dec->height;
ist->resample_width = dec->width;
ist->resample_pix_fmt = dec->pix_fmt;
MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
if (framerate && av_parse_video_rate(&ist->framerate,
framerate) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
framerate);
exit_program(1);
}
ist->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
case AVMEDIA_TYPE_AUDIO:
guess_input_channel_layout(ist);
ist->resample_sample_fmt = dec->sample_fmt;
ist->resample_sample_rate = dec->sample_rate;
ist->resample_channels = dec->channels;
ist->resample_channel_layout = dec->channel_layout;
break;
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
break;
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
default:
abort();
}
}
}
static void assert_file_overwrite(const char *filename)