+
+int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
+{
+ int ret;
+ FILE *f = fopen(filename, "rb");
+
+ if (!f) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename,
+ strerror(errno));
+ return AVERROR(errno);
+ }
+ fseek(f, 0, SEEK_END);
+ *size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ *bufptr = av_malloc(*size + 1);
+ if (!*bufptr) {
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate file buffer\n");
+ fclose(f);
+ return AVERROR(ENOMEM);
+ }
+ ret = fread(*bufptr, 1, *size, f);
+ if (ret < *size) {
+ av_free(*bufptr);
+ if (ferror(f)) {
+ av_log(NULL, AV_LOG_ERROR, "Error while reading file '%s': %s\n",
+ filename, strerror(errno));
+ ret = AVERROR(errno);
+ } else
+ ret = AVERROR_EOF;
+ } else {
+ ret = 0;
+ (*bufptr)[*size++] = '\0';
+ }
+
+ fclose(f);
+ return ret;
+}
+
+void init_pts_correction(PtsCorrectionContext *ctx)
+{
+ ctx->num_faulty_pts = ctx->num_faulty_dts = 0;
+ ctx->last_pts = ctx->last_dts = INT64_MIN;
+}
+
+int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t reordered_pts,
+ int64_t dts)
+{
+ int64_t pts = AV_NOPTS_VALUE;
+
+ if (dts != AV_NOPTS_VALUE) {
+ ctx->num_faulty_dts += dts <= ctx->last_dts;
+ ctx->last_dts = dts;
+ }
+ if (reordered_pts != AV_NOPTS_VALUE) {
+ ctx->num_faulty_pts += reordered_pts <= ctx->last_pts;
+ ctx->last_pts = reordered_pts;
+ }
+ if ((ctx->num_faulty_pts<=ctx->num_faulty_dts || dts == AV_NOPTS_VALUE)
+ && reordered_pts != AV_NOPTS_VALUE)
+ pts = reordered_pts;
+ else
+ pts = dts;
+
+ return pts;
+}
+
+FILE *get_preset_file(char *filename, size_t filename_size,
+ const char *preset_name, int is_path,
+ const char *codec_name)
+{
+ FILE *f = NULL;
+ int i;
+ const char *base[3] = { getenv("AVCONV_DATADIR"),
+ getenv("HOME"),
+ AVCONV_DATADIR, };
+
+ if (is_path) {
+ av_strlcpy(filename, preset_name, filename_size);
+ f = fopen(filename, "r");
+ } else {
+ for (i = 0; i < 3 && !f; i++) {
+ if (!base[i])
+ continue;
+ snprintf(filename, filename_size, "%s%s/%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", preset_name);
+ f = fopen(filename, "r");
+ if (!f && codec_name) {
+ snprintf(filename, filename_size,
+ "%s%s/%s-%s.avpreset",
+ base[i], i != 1 ? "" : "/.avconv", codec_name,
+ preset_name);
+ f = fopen(filename, "r");
+ }
+ }
+ }
+
+ return f;
+}
+
+int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
+{
+ if (*spec <= '9' && *spec >= '0') /* opt:index */
+ return strtol(spec, NULL, 0) == st->index;
+ else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
+ *spec == 't') { /* opt:[vasdt] */
+ enum AVMediaType type;
+
+ switch (*spec++) {
+ case 'v': type = AVMEDIA_TYPE_VIDEO; break;
+ case 'a': type = AVMEDIA_TYPE_AUDIO; break;
+ case 's': type = AVMEDIA_TYPE_SUBTITLE; break;
+ case 'd': type = AVMEDIA_TYPE_DATA; break;
+ case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
+ default: av_assert0(0);
+ }
+ if (type != st->codec->codec_type)
+ return 0;
+ if (*spec++ == ':') { /* possibly followed by :index */
+ int i, index = strtol(spec, NULL, 0);
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->codec->codec_type == type && index-- == 0)
+ return i == st->index;
+ return 0;
+ }
+ return 1;
+ } else if (*spec == 'p' && *(spec + 1) == ':') {
+ int prog_id, i, j;
+ char *endptr;
+ spec += 2;
+ prog_id = strtol(spec, &endptr, 0);
+ for (i = 0; i < s->nb_programs; i++) {
+ if (s->programs[i]->id != prog_id)
+ continue;
+
+ if (*endptr++ == ':') {
+ int stream_idx = strtol(endptr, NULL, 0);
+ return stream_idx >= 0 &&
+ stream_idx < s->programs[i]->nb_stream_indexes &&
+ st->index == s->programs[i]->stream_index[stream_idx];
+ }
+
+ for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
+ if (st->index == s->programs[i]->stream_index[j])
+ return 1;
+ }
+ return 0;
+ } else if (!*spec) /* empty specifier, matches everything */
+ return 1;
+
+ av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
+ return AVERROR(EINVAL);
+}
+
+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);
+ if (!codec)
+ return NULL;
+
+ switch (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;
+ }
+
+ 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;
+}
+
+AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
+ AVDictionary *codec_opts)
+{
+ int i;
+ AVDictionary **opts;
+
+ if (!s->nb_streams)
+ return NULL;
+ opts = av_mallocz(s->nb_streams * sizeof(*opts));
+ if (!opts) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not alloc memory for stream options.\n");
+ return NULL;
+ }
+ for (i = 0; i < s->nb_streams; i++)
+ opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codec->codec_id,
+ s, s->streams[i], NULL);
+ return opts;
+}
+
+void *grow_array(void *array, int elem_size, int *size, int new_size)
+{
+ if (new_size >= INT_MAX / elem_size) {
+ av_log(NULL, AV_LOG_ERROR, "Array too big.\n");
+ exit(1);
+ }
+ if (*size < new_size) {
+ uint8_t *tmp = av_realloc(array, new_size*elem_size);
+ if (!tmp) {
+ av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
+ exit(1);
+ }
+ memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
+ *size = new_size;
+ return tmp;
+ }
+ return array;
+}
+
+static int alloc_buffer(FrameBuffer **pool, AVCodecContext *s, FrameBuffer **pbuf)
+{
+ FrameBuffer *buf = av_mallocz(sizeof(*buf));
+ int i, ret;
+ 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:
+ * 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 if (buf->base[i])
+ 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->pool = pool;
+
+ *pbuf = buf;
+ return 0;
+}
+
+int codec_get_buffer(AVCodecContext *s, AVFrame *frame)
+{
+ FrameBuffer **pool = s->opaque;
+ FrameBuffer *buf;
+ int ret, i;
+
+ if (!*pool && (ret = alloc_buffer(pool, s, pool)) < 0)
+ return ret;
+
+ buf = *pool;
+ *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);
+ if ((ret = alloc_buffer(pool, s, &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;
+ frame->width = buf->w;
+ frame->height = buf->h;
+ frame->format = buf->pix_fmt;
+ frame->sample_aspect_ratio = s->sample_aspect_ratio;
+
+ 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 unref_buffer(FrameBuffer *buf)
+{
+ FrameBuffer **pool = buf->pool;
+
+ av_assert0(buf->refcount);
+ buf->refcount--;
+ if (!buf->refcount) {
+ buf->next = *pool;
+ *pool = buf;
+ }
+}
+
+void codec_release_buffer(AVCodecContext *s, AVFrame *frame)
+{
+ FrameBuffer *buf = frame->opaque;
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
+ frame->data[i] = NULL;
+
+ unref_buffer(buf);
+}
+
+void filter_release_buffer(AVFilterBuffer *fb)
+{
+ FrameBuffer *buf = fb->priv;
+ av_free(fb);
+ unref_buffer(buf);
+}
+
+void free_buffer_pool(FrameBuffer **pool)
+{
+ FrameBuffer *buf = *pool;
+ while (buf) {
+ *pool = buf->next;
+ av_freep(&buf->base[0]);
+ av_free(buf);
+ buf = *pool;
+ }
+}