int opt_default(const char *opt, const char *arg) { const AVOption *oc, *of, *os; char opt_stripped[128]; const char *p; const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(), *sc; if (!(p = strchr(opt, ':'))) p = opt + strlen(opt); av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1)); if ((oc = av_opt_find(&cc, opt_stripped, NULL, 0, AV_OPT_SEARCH_CHILDREN|AV_OPT_SEARCH_FAKE_OBJ)) || ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') && (oc = av_opt_find(&cc, opt+1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) av_dict_set(&codec_opts, opt, arg, FLAGS(oc)); if ((of = av_opt_find(&fc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&format_opts, opt, arg, FLAGS(of)); #if CONFIG_SWSCALE sc = sws_get_class(); if ((os = av_opt_find(&sc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { // XXX we only support sws_flags, not arbitrary sws options int ret = av_set_string3(sws_opts, opt, arg, 1, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); return ret; } } #endif if (oc || of || os) return 0; av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt); return AVERROR_OPTION_NOT_FOUND; }
static int opt_default2(const char *opt, const char *arg) { const AVOption *o; if ((o = av_opt_find(avcodec_opts[0], opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) { if (o->flags & AV_OPT_FLAG_VIDEO_PARAM) av_dict_set(&video_opts, opt, arg, FLAGS); if (o->flags & AV_OPT_FLAG_AUDIO_PARAM) av_dict_set(&audio_opts, opt, arg, FLAGS); if (o->flags & AV_OPT_FLAG_SUBTITLE_PARAM) av_dict_set(&sub_opts, opt, arg, FLAGS); } else if ((o = av_opt_find(avformat_opts, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) av_dict_set(&format_opts, opt, arg, FLAGS); else if ((o = av_opt_find(sws_opts, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) { // XXX we only support sws_flags, not arbitrary sws options int ret = av_set_string3(sws_opts, opt, arg, 1, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); return ret; } } if (!o) { SET_PREFIXED_OPTS('v', AV_OPT_FLAG_VIDEO_PARAM, video_opts) SET_PREFIXED_OPTS('a', AV_OPT_FLAG_AUDIO_PARAM, audio_opts) SET_PREFIXED_OPTS('s', AV_OPT_FLAG_SUBTITLE_PARAM, sub_opts) } if (o) return 0; fprintf(stderr, "Unrecognized option '%s'\n", opt); return AVERROR_OPTION_NOT_FOUND; }
static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags) { AVFormatContext *s = obj; AVInputFormat *ifmt = NULL; AVOutputFormat *ofmt = NULL; if (s->priv_data) { if ((s->iformat && !s->iformat->priv_class) || (s->oformat && !s->oformat->priv_class)) return NULL; return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags); } while ((ifmt = av_iformat_next(ifmt))) { const AVOption *o; if (ifmt->priv_class && (o = av_opt_find(&ifmt->priv_class, name, unit, opt_flags, search_flags))) return o; } while ((ofmt = av_oformat_next(ofmt))) { const AVOption *o; if (ofmt->priv_class && (o = av_opt_find(&ofmt->priv_class, name, unit, opt_flags, search_flags))) return o; } return NULL; }
int opt_default(const char *opt, const char *arg){ int type; int ret= 0; const AVOption *o= NULL; int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0}; for(type=0; *avcodec_opts && type<AVMEDIA_TYPE_NB && ret>= 0; type++){ const AVOption *o2 = av_opt_find(avcodec_opts[0], opt, NULL, opt_types[type], 0); if(o2) ret = av_set_string3(avcodec_opts[type], opt, arg, 1, &o); } if(!o && avformat_opts) ret = av_set_string3(avformat_opts, opt, arg, 1, &o); if(!o && sws_opts) ret = av_set_string3(sws_opts, opt, arg, 1, &o); if(!o){ if (opt[0] == 'a' && avcodec_opts[AVMEDIA_TYPE_AUDIO]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_AUDIO], opt+1, arg, 1, &o); else if(opt[0] == 'v' && avcodec_opts[AVMEDIA_TYPE_VIDEO]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_VIDEO], opt+1, arg, 1, &o); else if(opt[0] == 's' && avcodec_opts[AVMEDIA_TYPE_SUBTITLE]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_SUBTITLE], opt+1, arg, 1, &o); } if (o && ret < 0) { fprintf(stderr, "Invalid value '%s' for option '%s'\n", arg, opt); exit(1); } if (!o) { AVCodec *p = NULL; AVOutputFormat *oformat = NULL; while ((p=av_codec_next(p))){ const AVClass *c = p->priv_class; if(c && av_opt_find(&c, opt, NULL, 0, 0)) break; } if (!p) { while ((oformat = av_oformat_next(oformat))) { const AVClass *c = oformat->priv_class; if (c && av_opt_find(&c, opt, NULL, 0, 0)) break; } } } if ((ret = opt_default2(opt, arg)) < 0) return ret; // av_log(NULL, AV_LOG_ERROR, "%s:%s: %f 0x%0X\n", opt, arg, av_get_double(avcodec_opts, opt, NULL), (int)av_get_int(avcodec_opts, opt, NULL)); //FIXME we should always use avcodec_opts, ... for storing options so there will not be any need to keep track of what i set over this opt_values= av_realloc(opt_values, sizeof(void*)*(opt_name_count+1)); opt_values[opt_name_count]= o ? NULL : av_strdup(arg); opt_names= av_realloc(opt_names, sizeof(void*)*(opt_name_count+1)); opt_names[opt_name_count++]= o ? o->name : av_strdup(opt); if ((*avcodec_opts && avcodec_opts[0]->debug) || (avformat_opts && avformat_opts->debug)) av_log_set_level(AV_LOG_DEBUG); return 0; }
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, AVCodec *codec) { AVDictionary *ret = NULL; AVDictionaryEntry *t = NULL; int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; char prefix = 0; const AVClass *cc = avcodec_get_class(); if (!codec) codec = s->oformat ? avcodec_find_encoder(codec_id) : avcodec_find_decoder(codec_id); switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: prefix = 'v'; flags |= AV_OPT_FLAG_VIDEO_PARAM; break; case AVMEDIA_TYPE_AUDIO: prefix = 'a'; flags |= AV_OPT_FLAG_AUDIO_PARAM; break; case AVMEDIA_TYPE_SUBTITLE: prefix = 's'; flags |= AV_OPT_FLAG_SUBTITLE_PARAM; break; default: break; } while ((t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX))) { char *p = strchr(t->key, ':'); /* check stream specification in opt name */ if (p) switch (check_stream_specifier(s, st, p + 1)) { case 1: *p = 0; break; case 0: continue; default: return NULL; } if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) || (codec && codec->priv_class && av_opt_find(&codec->priv_class, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&ret, t->key, t->value, 0); else if (t->key[0] == prefix && av_opt_find(&cc, t->key + 1, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ)) av_dict_set(&ret, t->key + 1, t->value, 0); if (p) *p = ':'; } return ret; }
static av_cold int init(AVFilterContext *ctx, AVDictionary **opts) { ResampleContext *s = ctx->priv; const AVClass *avr_class = avresample_get_class(); AVDictionaryEntry *e = NULL; while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) { if (av_opt_find(&avr_class, e->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ | AV_OPT_SEARCH_CHILDREN)) av_dict_set(&s->options, e->key, e->value, 0); } e = NULL; while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX))) av_dict_set(opts, e->key, NULL, 0); /* do not allow the user to override basic format options */ av_dict_set(&s->options, "in_channel_layout", NULL, 0); av_dict_set(&s->options, "out_channel_layout", NULL, 0); av_dict_set(&s->options, "in_sample_fmt", NULL, 0); av_dict_set(&s->options, "out_sample_fmt", NULL, 0); av_dict_set(&s->options, "in_sample_rate", NULL, 0); av_dict_set(&s->options, "out_sample_rate", NULL, 0); return 0; }
IProperty* Property :: getPropertyMetaData(void *aContext, const char *aName) { IProperty *retval = 0; const AVOption* last = 0; try { if (!aContext) throw std::runtime_error("no context passed in"); if (!aName || !*aName) throw std::runtime_error("no property name passed in"); last = av_opt_find(aContext, aName, 0, 0, 0); if (last) { if (last->type != AV_OPT_TYPE_CONST) { retval = Property::make(av_opt_next(aContext, 0), last); } } } catch (std::exception & e) { VS_LOG_DEBUG("Error: %s", e.what()); VS_REF_RELEASE(retval); } return retval; }
static int ffserver_save_avoption(const char *opt, const char *arg, AVDictionary **dict, int type, FFServerConfig *config, int line_num) { int ret = 0; AVDictionaryEntry *e; const AVOption *o = av_opt_find(config->dummy_ctx, opt, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN); if (!o) { report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Option not found: %s\n", opt); } else if ((ret = av_opt_set(config->dummy_ctx, opt, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Invalid value for option %s (%s): %s\n", opt, arg, av_err2str(ret)); } else if ((e = av_dict_get(*dict, opt, NULL, 0))) { if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-')) return av_dict_set(dict, opt, arg, AV_DICT_APPEND); report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Redeclaring value of the option %s, previous value: %s\n", opt, e->value); } else if (av_dict_set(dict, opt, arg, 0) < 0) { return AVERROR(ENOMEM); } return 0; }
static int ffserver_opt_default(const char *opt, const char *arg, AVCodecContext *avctx, int type) { int ret = 0; const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0); if(o) ret = av_opt_set(avctx, opt, arg, 0); return ret; }
static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags) { AVCodecContext *s = obj; AVCodec *c = NULL; if (s->priv_data) { if (s->codec->priv_class) return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags); return NULL; } while ((c = av_codec_next(c))) { const AVOption *o; if (c->priv_class && (o = av_opt_find(&c->priv_class, name, unit, opt_flags, search_flags))) return o; } return NULL; }
static int ffm_write_recommended_config(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, const char *configuration) { int ret; const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id); AVIOContext *tmp; AVDictionaryEntry *t = NULL; AVDictionary *all = NULL, *comm = NULL, *prv = NULL; char *buf = NULL; if (!enc || !enc->priv_class || !enc->priv_data_size) { /* codec is not known/has no private options, so save everything as common options */ if (avio_open_dyn_buf(&tmp) < 0) return AVERROR(ENOMEM); avio_put_str(tmp, configuration); write_header_chunk(pb, tmp, tag); return 0; } if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0) return ret; while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) { if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0) goto fail; } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0) goto fail; } if (comm) { if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 || (ret = avio_open_dyn_buf(&tmp)) < 0) goto fail; avio_put_str(tmp, buf); av_freep(&buf); write_header_chunk(pb, tmp, tag); } if (prv) { if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 || (ret = avio_open_dyn_buf(&tmp)) < 0) goto fail; avio_put_str(tmp, buf); write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); } fail: av_free(buf); av_dict_free(&all); av_dict_free(&comm); av_dict_free(&prv); return ret; }
IProperty * Property :: getFlagConstant(const char* aName) { IProperty *retval = 0; try { if (getType() != IProperty::PROPERTY_FLAGS) throw std::runtime_error("flag is not of type PROPERTY_FLAGS"); // now, iterate through all options, counting all CONSTS that belong // to the same unit as this option const char* unit = getUnit(); if (!unit || !*unit) throw std::runtime_error("flag doesn't have a unit setting, so can't tell what constants"); AVClass fakeClass; fakeClass.class_name="XuggleFakeClass"; fakeClass.item_name = fakeContextToName; fakeClass.option = mOptionStart; const AVOption* last = 0; last = av_opt_find(&fakeClass, aName, unit, 0, 0); if (last) { if (last->type == AV_OPT_TYPE_CONST) { retval = Property::make(av_opt_next(&fakeClass, 0), last); } } } catch (std::exception & e) { VS_LOG_DEBUG("Error: %s", e.what()); VS_REF_RELEASE(retval); } return retval; }
static int init(sh_audio_t *sh, const char *decoder) { int x, in_size, srate, bps, *dtshd_rate; unsigned char *start; double pts; AVFormatContext *lavf_ctx = NULL; AVStream *stream = NULL; const AVOption *opt = NULL; struct spdifContext *spdif_ctx = NULL; spdif_ctx = av_mallocz(sizeof(*spdif_ctx)); if (!spdif_ctx) goto fail; spdif_ctx->lavf_ctx = avformat_alloc_context(); if (!spdif_ctx->lavf_ctx) goto fail; sh->context = spdif_ctx; lavf_ctx = spdif_ctx->lavf_ctx; lavf_ctx->oformat = av_guess_format(FILENAME_SPDIFENC, NULL, NULL); if (!lavf_ctx->oformat) goto fail; lavf_ctx->priv_data = av_mallocz(lavf_ctx->oformat->priv_data_size); if (!lavf_ctx->priv_data) goto fail; lavf_ctx->pb = avio_alloc_context(spdif_ctx->pb_buffer, OUTBUF_SIZE, 1, spdif_ctx, read_packet, write_packet, seek); if (!lavf_ctx->pb) goto fail; stream = avformat_new_stream(lavf_ctx, 0); if (!stream) goto fail; lavf_ctx->duration = AV_NOPTS_VALUE; lavf_ctx->start_time = AV_NOPTS_VALUE; lavf_ctx->streams[0]->codec->codec_id = mp_codec_to_av_codec_id(decoder); lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) { mp_msg(MSGT_DECAUDIO,MSGL_INFO, "This codec is not supported by spdifenc.\n"); goto fail; } // get sample_rate & bitrate from parser x = ds_get_packet_pts(sh->ds, &start, &pts); in_size = x; if (x <= 0) { pts = MP_NOPTS_VALUE; x = 0; } ds_parse(sh->ds, &start, &x, pts, 0); srate = 48000; //fake value bps = 768000/8; //fake value if (x && sh->avctx) { // we have parser and large enough buffer if (sh->avctx->sample_rate < 44100) { mp_msg(MSGT_DECAUDIO,MSGL_INFO, "This stream sample_rate[%d Hz] may be broken. " "Force reset 48000Hz.\n", sh->avctx->sample_rate); srate = 48000; //fake value } else srate = sh->avctx->sample_rate; bps = sh->avctx->bit_rate/8; } sh->ds->buffer_pos -= in_size; switch (lavf_ctx->streams[0]->codec->codec_id) { case AV_CODEC_ID_AAC: spdif_ctx->iec61937_packet_size = 16384; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = srate; sh->channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_AC3: spdif_ctx->iec61937_packet_size = 6144; sh->sample_format = AF_FORMAT_AC3_LE; sh->samplerate = srate; sh->channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_DTS: if(sh->opts->dtshd) { opt = av_opt_find(&lavf_ctx->oformat->priv_class, "dtshd_rate", NULL, 0, 0); if (!opt) goto fail; dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) + opt->offset); *dtshd_rate = 192000*4; spdif_ctx->iec61937_packet_size = 32768; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; // DTS core require 48000 sh->channels = 2*4; sh->i_bps = bps; } else { spdif_ctx->iec61937_packet_size = 32768; sh->sample_format = AF_FORMAT_AC3_LE; sh->samplerate = srate; sh->channels = 2; sh->i_bps = bps; } break; case AV_CODEC_ID_EAC3: spdif_ctx->iec61937_packet_size = 24576; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; sh->channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_MP3: spdif_ctx->iec61937_packet_size = 4608; sh->sample_format = AF_FORMAT_MPEG2; sh->samplerate = srate; sh->channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_TRUEHD: spdif_ctx->iec61937_packet_size = 61440; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; sh->channels = 8; sh->i_bps = bps; break; default: break; } return 1; fail: uninit(sh); return 0; }
//---------------------------------------------------------------- // main_utf8 // int main_utf8(int argc, char **argv) { const char *input = NULL; const char *output_prefix = ""; double target_segment_duration = 0.0; char *segment_duration_check = NULL; const char *playlist_filename = NULL; const char *http_prefix = ""; long max_tsfiles = 0; char *max_tsfiles_check = NULL; double prev_segment_time = 0.0; double segment_duration = 0.0; unsigned int output_index = 0; const AVClass *fc = avformat_get_class(); AVDictionary *format_opts = NULL; AVOutputFormat *ofmt = NULL; AVFormatContext *ic = NULL; AVFormatContext *oc = NULL; AVStream *video_st = NULL; AVStream *audio_st = NULL; AVCodec *codec = NULL; char *output_filename = NULL; char *pid_filename = NULL; int video_index = -1; int audio_index = -1; int kill_file = 0; int decode_done = 0; int ret = 0; int i = 0; TSMStreamLace * streamLace = NULL; TSMPlaylist * playlist = NULL; const double segment_duration_error_tolerance = 0.05; double extra_duration_needed = 0; int strict_segment_duration = 0; av_log_set_level(AV_LOG_INFO); for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; input = argv[i]; } else if (strcmp(argv[i], "-o") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; output_prefix = argv[i]; } else if (strcmp(argv[i], "-d") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -d parameter"); i++; target_segment_duration = strtod(argv[i], &segment_duration_check); if (segment_duration_check == argv[i] || target_segment_duration == HUGE_VAL || target_segment_duration == -HUGE_VAL) { usage3(argv, "invalid segment duration: ", argv[i]); } } else if (strcmp(argv[i], "-x") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -x parameter"); i++; playlist_filename = argv[i]; } else if (strcmp(argv[i], "-p") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -p parameter"); i++; http_prefix = argv[i]; } else if (strcmp(argv[i], "-w") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -w parameter"); i++; max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10); if (max_tsfiles_check == argv[i] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) { usage3(argv, "invalid live stream max window size: ", argv[i]); } } else if (strcmp(argv[i], "-P") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -P parameter"); i++; pid_filename = argv[i]; } else if (strcmp(argv[i], "--watch-for-kill-file") == 0) { // end program when it finds a file with name 'kill': kill_file = 1; } else if (strcmp(argv[i], "--strict-segment-duration") == 0) { // force segment creation on non-keyframe boundaries: strict_segment_duration = 1; } else if (strcmp(argv[i], "--avformat-option") == 0) { const AVOption *of; const char *opt; const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; opt = argv[i]; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; arg = argv[i]; if ((of = av_opt_find(&fc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&format_opts, opt, arg, (of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0); else usage3(argv, "unknown --avformat-option parameter: ", opt); } else if (strcmp(argv[i], "--loglevel") == 0) { const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --loglevel parameter"); i++; arg = argv[i]; if (loglevel(arg)) usage3(argv, "unknown --loglevel parameter: ", arg); } } if (!input) { usage(argv, "-i input file parameter must be specified"); } if (!playlist_filename) { usage(argv, "-x m3u8 playlist file parameter must be specified"); } if (target_segment_duration == 0.0) { usage(argv, "-d segment duration parameter must be specified"); } // Create PID file if (pid_filename) { FILE* pid_file = fopen_utf8(pid_filename, "wb"); if (pid_file) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } } av_register_all(); avformat_network_init(); if (!strcmp(input, "-")) { input = "pipe:"; } output_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15)); if (!output_filename) { fprintf(stderr, "Could not allocate space for output filenames\n"); goto error; } playlist = createPlaylist(max_tsfiles, target_segment_duration, http_prefix); if (!playlist) { fprintf(stderr, "Could not allocate space for m3u8 playlist structure\n"); goto error; } ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL); if (ret != 0) { fprintf(stderr, "Could not open input file, make sure it is an mpegts or mp4 file: %d\n", ret); goto error; } av_dict_free(&format_opts); if (avformat_find_stream_info(ic, NULL) < 0) { fprintf(stderr, "Could not read stream information\n"); goto error; } #if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \ LIBAVFORMAT_VERSION_MINOR >= 45) ofmt = av_guess_format("mpegts", NULL, NULL); #else ofmt = guess_format("mpegts", NULL, NULL); #endif if (!ofmt) { fprintf(stderr, "Could not find MPEG-TS muxer\n"); goto error; } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "Could not allocated output context\n"); goto error; } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } av_dump_format(oc, 0, output_prefix, 1); if (video_index >=0) { codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open2(video_st->codec, codec, NULL) < 0) { fprintf(stderr, "Could not open video decoder, key frames will not be honored\n"); } } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); goto error; } if (avformat_write_header(oc, NULL)) { fprintf(stderr, "Could not write mpegts header to first output file\n"); goto error; } prev_segment_time = (double)(ic->start_time) / (double)(AV_TIME_BASE); streamLace = createStreamLace(ic->nb_streams); do { double segment_time = 0.0; AVPacket packet; double packetStartTime = 0.0; double packetDuration = 0.0; if (!decode_done) { decode_done = av_read_frame(ic, &packet); if (!decode_done) { if (packet.stream_index != video_index && packet.stream_index != audio_index) { av_free_packet(&packet); continue; } double timeStamp = (double)(packet.pts) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Could not duplicate packet\n"); av_free_packet(&packet); break; } insertPacket(streamLace, &packet, timeStamp); } } if (countPackets(streamLace) < 50 && !decode_done) { /* allow the queue to fill up so that the packets can be sorted properly */ continue; } if (!removePacket(streamLace, &packet)) { if (decode_done) { /* the queue is empty, we are done */ break; } assert(decode_done); continue; } packetStartTime = (double)(packet.pts) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); packetDuration = (double)(packet.duration) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); #if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG)) if (av_log_get_level() >= AV_LOG_VERBOSE) fprintf(stderr, "stream %i, packet [%f, %f)\n", packet.stream_index, packetStartTime, packetStartTime + packetDuration); #endif segment_duration = packetStartTime + packetDuration - prev_segment_time; // NOTE: segments are supposed to start on a keyframe. // If the keyframe interval and segment duration do not match // forcing the segment creation for "better seeking behavior" // will result in decoding artifacts after seeking or stream switching. if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) { segment_time = packetStartTime; } else if (video_index < 0) { segment_time = packetStartTime; } else { segment_time = prev_segment_time; } if (segment_time - prev_segment_time + segment_duration_error_tolerance > target_segment_duration + extra_duration_needed) { avio_flush(oc->pb); avio_close(oc->pb); // Keep track of accumulated rounding error to account for it in later chunks. double segment_duration = segment_time - prev_segment_time; int rounded_segment_duration = (int)(segment_duration + 0.5); extra_duration_needed += (double)rounded_segment_duration - segment_duration; updatePlaylist(playlist, playlist_filename, output_filename, output_index, rounded_segment_duration); snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); break; } // close when we find the 'kill' file if (kill_file) { FILE* fp = fopen("kill", "rb"); if (fp) { fprintf(stderr, "user abort: found kill file\n"); fclose(fp); remove("kill"); decode_done = 1; removeAllPackets(streamLace); } } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "Warning: Could not write frame of stream\n"); } else if (ret > 0) { fprintf(stderr, "End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done || countPackets(streamLace) > 0); av_write_trailer(oc); if (video_index >= 0) { avcodec_close(video_st->codec); } for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } avio_close(oc->pb); av_free(oc); updatePlaylist(playlist, playlist_filename, output_filename, output_index, segment_duration); closePlaylist(playlist); releasePlaylist(&playlist); if (pid_filename) { remove(pid_filename); } return 0; error: if (pid_filename) { remove(pid_filename); } return 1; }
static int process_options(AVFilterContext *ctx, AVDictionary **options, const char *args) { const AVOption *o = NULL; int ret, count = 0; char *av_uninit(parsed_key), *av_uninit(value); const char *key; int offset= -1; if (!args) return 0; while (*args) { const char *shorthand = NULL; o = av_opt_next(ctx->priv, o); if (o) { if (o->type == AV_OPT_TYPE_CONST || o->offset == offset) continue; offset = o->offset; shorthand = o->name; } ret = av_opt_get_key_value(&args, "=", ":", shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, &parsed_key, &value); if (ret < 0) { if (ret == AVERROR(EINVAL)) av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args); else av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args, av_err2str(ret)); return ret; } if (*args) args++; if (parsed_key) { key = parsed_key; while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */ } else { key = shorthand; } av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); if (av_opt_find(ctx, key, NULL, 0, 0)) { ret = av_opt_set(ctx, key, value, 0); if (ret < 0) { av_free(value); av_free(parsed_key); return ret; } } else { av_dict_set(options, key, value, 0); if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) { if (ret == AVERROR_OPTION_NOT_FOUND) av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); av_free(value); av_free(parsed_key); return ret; } } } av_free(value); av_free(parsed_key); count++; } if (ctx->enable_str) { ret = set_enable_expr(ctx, ctx->enable_str); if (ret < 0) return ret; } return count; }
int opt_default(const char *opt, const char *arg){ int type; int ret= 0; const AVOption *o= NULL; int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0}; AVCodec *p = NULL; AVOutputFormat *oformat = NULL; AVInputFormat *iformat = NULL; while ((p = av_codec_next(p))) { const AVClass *c = p->priv_class; if (c && av_find_opt(&c, opt, NULL, 0, 0)) break; } if (p) goto out; while ((oformat = av_oformat_next(oformat))) { const AVClass *c = oformat->priv_class; if (c && av_find_opt(&c, opt, NULL, 0, 0)) break; } if (oformat) goto out; while ((iformat = av_iformat_next(iformat))) { const AVClass *c = iformat->priv_class; if (c && av_find_opt(&c, opt, NULL, 0, 0)) break; } if (iformat) goto out; for(type=0; *avcodec_opts && type<AVMEDIA_TYPE_NB && ret>= 0; type++){ const AVOption *o2 = av_opt_find(avcodec_opts[0], opt, NULL, opt_types[type], 0); if(o2) ret = av_set_string3(avcodec_opts[type], opt, arg, 1, &o); } if(!o && avformat_opts) ret = av_set_string3(avformat_opts, opt, arg, 1, &o); if(!o && sws_opts) ret = av_set_string3(sws_opts, opt, arg, 1, &o); if(!o){ if (opt[0] == 'a' && avcodec_opts[AVMEDIA_TYPE_AUDIO]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_AUDIO], opt+1, arg, 1, &o); else if(opt[0] == 'v' && avcodec_opts[AVMEDIA_TYPE_VIDEO]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_VIDEO], opt+1, arg, 1, &o); else if(opt[0] == 's' && avcodec_opts[AVMEDIA_TYPE_SUBTITLE]) ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_SUBTITLE], opt+1, arg, 1, &o); if (ret >= 0) opt += 1; } if (o && ret < 0) { fprintf(stderr, "Invalid value '%s' for option '%s'\n", arg, opt); exit(1); } if (!o) { fprintf(stderr, "Unrecognized option '%s'\n", opt); exit(1); } out: if ((ret = opt_default2(opt, arg)) < 0) return ret; // av_log(NULL, AV_LOG_ERROR, "%s:%s: %f 0x%0X\n", opt, arg, av_get_double(avcodec_opts, opt, NULL), (int)av_get_int(avcodec_opts, opt, NULL)); opt_values= av_realloc(opt_values, sizeof(void*)*(opt_name_count+1)); opt_values[opt_name_count] = av_strdup(arg); opt_names= av_realloc(opt_names, sizeof(void*)*(opt_name_count+1)); opt_names[opt_name_count++] = av_strdup(opt); if ((*avcodec_opts && avcodec_opts[0]->debug) || (avformat_opts && avformat_opts->debug)) av_log_set_level(AV_LOG_DEBUG); return 0; }
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str) { AVCodecContext c; const AVOption *o = 0; const AVOption *p = 0; char name_[128]; char *name; char *param; IDProperty *prop = NULL; avcodec_get_context_defaults3(&c, NULL); strncpy(name_, str, sizeof(name_)); name = name_; while (*name == ' ') name++; param = strchr(name, ':'); if (!param) { param = strchr(name, ' '); } if (param) { *param++ = 0; while (*param == ' ') param++; } o = av_opt_find(&c, name, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); if (!o) { PRINT("Ignoring unknown expert option %s\n", str); return 0; } if (param && o->type == AV_OPT_TYPE_CONST) { return 0; } if (param && o->type != AV_OPT_TYPE_CONST && o->unit) { p = av_opt_find(&c, param, o->unit, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); if (p) { prop = BKE_ffmpeg_property_add(rd, (char *) type, p, o); } else { PRINT("Ignoring unknown expert option %s\n", str); } } else { prop = BKE_ffmpeg_property_add(rd, (char *) type, o, NULL); } if (!prop) { return 0; } if (param && !p) { switch (prop->type) { case IDP_INT: IDP_Int(prop) = atoi(param); break; case IDP_FLOAT: IDP_Float(prop) = atof(param); break; case IDP_STRING: strncpy(IDP_String(prop), param, prop->len); break; } } return 1; }
static int ffserver_save_avoption(const char *opt, const char *arg, int type, FFServerConfig *config) { static int hinted = 0; int ret = 0; AVDictionaryEntry *e; const AVOption *o = NULL; const char *option = NULL; const char *codec_name = NULL; char buff[1024]; AVCodecContext *ctx; AVDictionary **dict; enum AVCodecID guessed_codec_id; switch (type) { case AV_OPT_FLAG_VIDEO_PARAM: ctx = config->dummy_vctx; dict = &config->video_opts; guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? config->guessed_video_codec_id : AV_CODEC_ID_H264; break; case AV_OPT_FLAG_AUDIO_PARAM: ctx = config->dummy_actx; dict = &config->audio_opts; guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? config->guessed_audio_codec_id : AV_CODEC_ID_AAC; break; default: av_assert0(0); } if (strchr(opt, ':')) { //explicit private option snprintf(buff, sizeof(buff), "%s", opt); codec_name = buff; if(!(option = strchr(buff, ':'))) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Syntax error. Unmatched ':'\n"); return -1; } buff[option - buff] = '\0'; option++; if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0) return ret; if (!ctx->codec || !ctx->priv_data) return -1; } else { option = opt; } o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN); if (!o && (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") || !strcmp(option, "video_size") || !strcmp(option, "codec_tag"))) o = av_opt_find(ctx, option, NULL, 0, 0); if (!o) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Option not found: '%s'\n", opt); if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) { hinted = 1; report_config_error(config->filename, config->line_num, AV_LOG_ERROR, NULL, "If '%s' is a codec private" "option, then prefix it with codec name, for " "example '%s:%s %s' or define codec earlier.\n", opt, avcodec_get_name(guessed_codec_id) ,opt, arg); } } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Invalid value for option %s (%s): %s\n", opt, arg, av_err2str(ret)); } else if ((e = av_dict_get(*dict, option, NULL, 0))) { if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-')) return av_dict_set(dict, option, arg, AV_DICT_APPEND); report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Redeclaring value of option '%s'." "Previous value was: '%s'.\n", opt, e->value); } else if (av_dict_set(dict, option, arg, 0) < 0) { return AVERROR(ENOMEM); } return 0; }
//---------------------------------------------------------------- // main_utf8 // int main_utf8(int argc, char **argv) { const char *input = NULL; const char *output_prefix = ""; double target_segment_duration = 0.0; char *segment_duration_check = NULL; const char *playlist_filename = NULL; const char *http_prefix = ""; long max_tsfiles = 0; char *max_tsfiles_check = NULL; double prev_segment_time = 0.0; double segment_duration = 0.0; unsigned int output_index = 1; const AVClass *fc = avformat_get_class(); AVDictionary *format_opts = NULL; AVOutputFormat *ofmt = NULL; AVFormatContext *ic = NULL; AVFormatContext *oc = NULL; AVStream *video_st = NULL; AVStream *audio_st = NULL; AVCodec *codec = NULL; char *output_filename = NULL; int if_save_keyframe = 0; //add by wanggm char *keyframeinfo_filename = NULL; //add by wanggm json_object *obj = NULL; //add by wanggm json_object *info_arr_obj = NULL; //add by wanggm int if_monitor_related_process = 0; //add by wanggm pid_t relatedProcessPid = 1; //add by wanggm char *pid_filename = NULL; int video_index = -1; int audio_index = -1; int kill_file = 0; int decode_done = 0; int ret = 0; int i = 0; TSMStreamLace * streamLace = NULL; TSMPlaylist * playlist = NULL; const double segment_duration_error_tolerance = 0.05; double extra_duration_needed = 0; int strict_segment_duration = 0; av_log_set_level(AV_LOG_INFO); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; input = argv[i]; } else if (strcmp(argv[i], "-o") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -o parameter"); i++; output_prefix = argv[i]; } else if (strcmp(argv[i], "-d") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -d parameter"); i++; target_segment_duration = strtod(argv[i], &segment_duration_check); if (segment_duration_check == argv[i] || target_segment_duration == HUGE_VAL || target_segment_duration == -HUGE_VAL){ usage3(argv, "invalid segment duration: ", argv[i]); } } else if (strcmp(argv[i], "-x") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -x parameter"); i++; playlist_filename = argv[i]; } else if (strcmp(argv[i], "-p") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -p parameter"); i++; http_prefix = argv[i]; } else if (strcmp(argv[i], "-w") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -w parameter"); i++; max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10); if (max_tsfiles_check == argv[i] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) { usage3(argv, "invalid live stream max window size: ", argv[i]); } } else if (strcmp(argv[i], "-P") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -P parameter"); i++; pid_filename = argv[i]; } else if (strcmp(argv[i], "--watch-for-kill-file") == 0) { // end program when it finds a file with name 'kill': kill_file = 1; } else if (strcmp(argv[i], "--strict-segment-duration") == 0) { // force segment creation on non-keyframe boundaries: strict_segment_duration = 1; } else if (strcmp(argv[i], "--avformat-option") == 0) { const AVOption *of; const char *opt; const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; opt = argv[i]; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; arg = argv[i]; if ((of = av_opt_find(&fc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&format_opts, opt, arg, (of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0); else usage3(argv, "unknown --avformat-option parameter: ", opt); } else if (strcmp(argv[i], "--loglevel") == 0) { const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --loglevel parameter"); i++; arg = argv[i]; if (loglevel(arg)) usage3(argv, "unknown --loglevel parameter: ", arg); } else if (strcmp(argv[i], "-k") == 0) { //add by wanggm for save key frame information into json file. if ((argc - i) <= 1) usage(argv, "could not parse -k parameter"); i++; if_save_keyframe = atoi(argv[i]); } else if( strcmp(argv[i], "-s") == 0) {//add by wanggm for set the start index of ts file. if ( (argc -i ) <= 1) usage(argv, "could not parse -s parmeter"); i++; char *output_index_check = NULL; output_index = strtol(argv[i], &output_index_check, 10); if ( output_index_check== argv[i] || output_index < 0 || output_index >= INT_MAX) { usage3(argv, "invalid start index of ts file: ", argv[i]); } } else if( strcmp(argv[i], "-m") == 0) { // add by wanggm for exit by monitor the process of which pid is given. if ((argc - i) <= 1) usage(argv, "could not parse -m parmeter"); i++; if_monitor_related_process = 1; unsigned int tmpPid= atoi(argv[i]); if( tmpPid > 0) { relatedProcessPid = (pid_t) tmpPid; fprintf(stdout, "%s I will exit when the process PID= %d exit.\n", getSystemTime(timeChar), relatedProcessPid); } } } if (!input) { usage(argv, "-i input file parameter must be specified"); } if (!playlist_filename) { usage(argv, "-x m3u8 playlist file parameter must be specified"); } if (target_segment_duration == 0.0) { usage(argv, "-d segment duration parameter must be specified"); } if( output_index <= 0 ) { output_index = 1; } if( 1 == if_monitor_related_process) { pthread_t id; pthread_create(&id, NULL, (void*)monitor_process, relatedProcessPid); } // Create PID file if (pid_filename) { FILE* pid_file = fopen_utf8(pid_filename, "wb"); if (pid_file) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } } av_register_all(); avformat_network_init(); if (!strcmp(input, "-")) { input = "pipe:"; } output_filename = (char*) malloc( sizeof(char) * (strlen(output_prefix) + 15)); //add by wanggm if( if_save_keyframe == 1) { keyframeinfo_filename = (char*) malloc( sizeof(char)* (strlen(output_prefix) + 15)); } if (!output_filename || (1 == if_save_keyframe && !keyframeinfo_filename)) { fprintf(stderr, "%s Could not allocate space for output filenames\n", getSystemTime( timeChar)); goto error; } playlist = createPlaylist(max_tsfiles, target_segment_duration, http_prefix); if (!playlist) { fprintf(stderr, "%s Could not allocate space for m3u8 playlist structure\n", getSystemTime( timeChar)); goto error; } ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL); if (ret != 0) { fprintf(stderr, "%sCould not open input file, make sure it is an mpegts or mp4 file: %d\n", getSystemTime(timeChar), ret); goto error; } av_dict_free(&format_opts); if (avformat_find_stream_info(ic, NULL) < 0) { fprintf(stderr, "%s Could not read stream information\n", getSystemTime( timeChar)); goto error; } #if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \ LIBAVFORMAT_VERSION_MINOR >= 45) ofmt = av_guess_format("mpegts", NULL, NULL); #else ofmt = guess_format("mpegts", NULL, NULL); #endif if (!ofmt) { fprintf(stderr, "%s Could not find MPEG-TS muxer\n", getSystemTime( timeChar)); goto error; } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "%s Could not allocated output context\n", getSystemTime( timeChar)); goto error; } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } av_dump_format(oc, 0, output_prefix, 1); if (video_index >= 0) { codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "%s Could not find video decoder, key frames will not be honored\n", getSystemTime( timeChar)); } if (avcodec_open2(video_st->codec, codec, NULL) < 0) { fprintf(stderr, "%s Could not open video decoder, key frames will not be honored\n", getSystemTime( timeChar)); } } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index); if( 1 == if_save_keyframe) { snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); obj = json_object_new_object(); info_arr_obj = create_json_header(obj); } if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar),output_filename); goto error; } if (avformat_write_header(oc, NULL)) { fprintf(stderr, "%s Could not write mpegts header to first output file\n", getSystemTime( timeChar)); goto error; } prev_segment_time = (double) (ic->start_time) / (double) (AV_TIME_BASE); streamLace = createStreamLace(ic->nb_streams); // add by houmr int continue_error_cnt = 0; //int pushcnt = 0; //int popcnt = 0; int tscnt = 0; int audiopktcnt = 0; int videopktcnt = 0; int kfcnt = 0; int errpktcnt = 0; ///////////////////////// do { double segment_time = 0.0; AVPacket packet; double packetStartTime = 0.0; double packetDuration = 0.0; if (!decode_done) { //fprintf(stdout, "%s av_read_frame() begin.\n", getSystemTime( timeChar)); decode_done = av_read_frame(ic, &packet); //fprintf(stdout, "%s av_read_frame() end. packet.size=%d stream_index=%d duration=%d\n", getSystemTime( timeChar), packet.size, packet.stream_index, packet.duration); //fprintf(stdout, "%s decode_done=%d\n", getSystemTime( timeChar),decode_done); if (!decode_done) { if (packet.stream_index != video_index && packet.stream_index != audio_index) { if( ++errpktcnt >= 10) { decode_done = 1; } fprintf(stderr, "%s packet is not video or audio, packet.stream_index=%d\n", getSystemTime( timeChar), packet.stream_index); av_free_packet(&packet); continue; } errpktcnt = 0; /*printf("orgin : index - %d\t pts = %s\t duration=%d\n", packet.stream_index, av_ts2str(packet.pts), packet.duration);*/ // add by houmr /*if (adjust_pts(&packet, video_index, audio_index) < 0) { av_free_packet(&packet); continue; } */ ///////////////////////////////////// double timeStamp = (double) (packet.pts) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); if (av_dup_packet(&packet) < 0) { fprintf(stderr, "%s Could not duplicate packet\n" ,getSystemTime( timeChar)); av_free_packet(&packet); break; } /* for(int i = 0; i < streamLace->numStreams; ++i) { fprintf(stdout, "streamLace[%d].size=%d\t", i, streamLace->streams[i]->size); } fprintf(stdout, "\n"); */ insertPacket(streamLace, &packet, timeStamp); } } if (countPackets(streamLace) < 50 && !decode_done) { /* allow the queue to fill up so that the packets can be sorted properly */ continue; } if (!removePacket(streamLace, &packet)) { fprintf(stdout, "%s get packet failed!!\n", getSystemTime( timeChar)); if (decode_done) { /* the queue is empty, we are done */ break; } assert(decode_done); continue; } //fprintf(stdout, "%s get 1 packet success. packet info: pts=%ld, dts=%ld\n", getSystemTime( timeChar), packet.pts, packet.dts); packetStartTime = (double) (packet.pts) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); packetDuration = (double) (packet.duration) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); #if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG)) if (av_log_get_level() >= AV_LOG_VERBOSE) fprintf(stderr, "%s stream %i, packet [%f, %f)\n", getSystemTime( timeChar), packet.stream_index, packetStartTime, packetStartTime + packetDuration); #endif segment_duration = packetStartTime + packetDuration - prev_segment_time; // NOTE: segments are supposed to start on a keyframe. // If the keyframe interval and segment duration do not match // forcing the segment creation for "better seeking behavior" // will result in decoding artifacts after seeking or stream switching. if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) { //This is video packet and ( packet is key frame or strict time is needed ) segment_time = packetStartTime; } else if (video_index < 0) { //This stream doesn't contain video stream segment_time = packetStartTime; } else { //This is a video packet or a video packet but not key frame segment_time = prev_segment_time; } //fprintf(stdout, "%s extra_duration_needed=%f\n", getSystemTime( timeChar), extra_duration_needed); if (segment_time - prev_segment_time + segment_duration_error_tolerance > target_segment_duration + extra_duration_needed) { fprintf(stdout, "%s segment_time=%lf prev_segment_time=%lf > target_segment_duration=%lf extra_duration_needed=%lf\n", getSystemTime( timeChar), segment_time, prev_segment_time, target_segment_duration, extra_duration_needed); fprintf(stdout, "%s File %s contains %d PES packet, of which %d are audio packet, %d are video packet within %d key frame.\n", getSystemTime( timeChar), output_filename, tscnt, audiopktcnt, videopktcnt, kfcnt); fflush(stdout); /* for(int i = 0; i < streamLace->numStreams; ++i) { fprintf(stdout, "%s streamLace[%d].size=%d\t", getSystemTime( timeChar), i, streamLace->streams[i]->size); } */ tscnt = audiopktcnt = videopktcnt = kfcnt = 0; avio_flush(oc->pb); avio_close(oc->pb); // Keep track of accumulated rounding error to account for it in later chunks. /* double segment_duration = segment_time - prev_segment_time; int rounded_segment_duration = (int) (segment_duration + 0.5); extra_duration_needed += (double) rounded_segment_duration - segment_duration; */ double seg_dur = segment_time - prev_segment_time; int rounded_segment_duration = (int) (seg_dur + 0.5); extra_duration_needed += (target_segment_duration - seg_dur - segment_duration_error_tolerance); //fprintf(stdout, "%s ________extra_duration_needed = %lf\n", getSystemTime( timeChar), extra_duration_needed); updatePlaylist(playlist, playlist_filename, output_filename, output_index, rounded_segment_duration); snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); //add by wanggm //Save the all the keyframe information into json file if( 1 == if_save_keyframe && NULL != obj) { save_json_to_file(keyframeinfo_filename, obj); obj = info_arr_obj = NULL; snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); } if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar), output_filename); break; } // close when we find the 'kill' file if (kill_file) { FILE* fp = fopen("kill", "rb"); if (fp) { fprintf(stderr, "%s user abort: found kill file\n", getSystemTime( timeChar)); fclose(fp); remove("kill"); decode_done = 1; removeAllPackets(streamLace); } } prev_segment_time = segment_time; } //add by wanggm. ++tscnt; if( video_index == packet.stream_index) { ++videopktcnt; if(1 == packet.flags) { ++kfcnt; if( 1 == if_save_keyframe) { //If it is key frame, it's information should be saved. //fprintf(stdout, "%s packet is keyframe, packet.pts=%ld\n", getSystemTime( timeChar), packet.pts); snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); if (NULL == obj && NULL == info_arr_obj) { obj = json_object_new_object(); info_arr_obj = create_json_header(obj); } avio_flush(oc->pb); //flush the previous data into ts file. int64_t offset = avio_tell(oc->pb); //Get the offset of this key frame in the file. save_keyframe_info(info_arr_obj, offset, packet.pts); //fprintf(stdout, "%s Keyframe.pos=%ld \tkeyframe.pts=%ld\n", getSystemTime( timeChar), offset, (long)packet.pts); } } }else if( audio_index == packet.stream_index) { ++audiopktcnt; } //fprintf(stdout, "%s packet is not keyframe.\n", getSystemTime( timeChar)); ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "%s Warning: Could not write frame of stream\n", getSystemTime( timeChar)); // add by houmr continue_error_cnt++; if (continue_error_cnt > 10) { av_free_packet(&packet); break; } } else if (ret > 0) { fprintf(stderr, "%s End of stream requested\n", getSystemTime( timeChar)); av_free_packet(&packet); break; } else { // add by houmr error continue_error_cnt = 0; //////////////////////// } av_free_packet(&packet); } while (!decode_done || countPackets(streamLace) > 0); av_write_trailer(oc); if (video_index >= 0) { avcodec_close(video_st->codec); } for (i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } avio_close(oc->pb); av_free(oc); updatePlaylist(playlist, playlist_filename, output_filename, output_index, segment_duration); closePlaylist(playlist); releasePlaylist(&playlist); //add by wanggm if( 1 == if_save_keyframe && obj != NULL) { save_json_to_file(keyframeinfo_filename, obj); } if (pid_filename) { remove(pid_filename); } fflush(stdout); fflush(stderr); return 0; error: if (pid_filename) { remove(pid_filename); } return 1; }