Skip to content
Snippets Groups Projects
cmdutils.c 54.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •     PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats",
                              AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);
    
        PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0,
                              GET_SAMPLE_RATE_NAME);
        PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats",
                              AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);
        PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts",
                              0, GET_CH_LAYOUT_DESC);
    
        if (c->priv_class) {
            show_help_children(c->priv_class,
                               AV_OPT_FLAG_ENCODING_PARAM |
                               AV_OPT_FLAG_DECODING_PARAM);
        }
    }
    
    
    static char get_media_type_char(enum AVMediaType type)
    {
        switch (type) {
            case AVMEDIA_TYPE_VIDEO:    return 'V';
            case AVMEDIA_TYPE_AUDIO:    return 'A';
            case AVMEDIA_TYPE_SUBTITLE: return 'S';
            default:                    return '?';
        }
    }
    
    static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
                                            int encoder)
    {
        while ((prev = av_codec_next(prev))) {
            if (prev->id == id &&
                (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev)))
                return prev;
        }
        return NULL;
    }
    
    static void print_codecs_for_id(enum AVCodecID id, int encoder)
    {
        const AVCodec *codec = NULL;
    
        printf(" (%s: ", encoder ? "encoders" : "decoders");
    
        while ((codec = next_codec_for_id(id, codec, encoder)))
            printf("%s ", codec->name);
    
        printf(")");
    }
    
    
    int show_codecs(void *optctx, const char *opt, const char *arg)
    
        const AVCodecDescriptor *desc = NULL;
    
    
        printf("Codecs:\n"
    
               " D..... = Decoding supported\n"
               " .E.... = Encoding supported\n"
               " ..V... = Video codec\n"
               " ..A... = Audio codec\n"
               " ..S... = Subtitle codec\n"
               " ...I.. = Intra frame-only codec\n"
               " ....L. = Lossy compression\n"
               " .....S = Lossless compression\n"
               " -------\n");
    
        while ((desc = avcodec_descriptor_next(desc))) {
            const AVCodec *codec = NULL;
    
            printf(avcodec_find_decoder(desc->id) ? "D" : ".");
            printf(avcodec_find_encoder(desc->id) ? "E" : ".");
    
            printf("%c", get_media_type_char(desc->type));
            printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
    
            printf((desc->props & AV_CODEC_PROP_LOSSY)      ? "L" : ".");
            printf((desc->props & AV_CODEC_PROP_LOSSLESS)   ? "S" : ".");
    
    
            printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
    
            /* print decoders/encoders when there's more than one or their
             * names are different from codec name */
            while ((codec = next_codec_for_id(desc->id, codec, 0))) {
                if (strcmp(codec->name, desc->name)) {
                    print_codecs_for_id(desc->id, 0);
                    break;
    
            }
            codec = NULL;
            while ((codec = next_codec_for_id(desc->id, codec, 1))) {
                if (strcmp(codec->name, desc->name)) {
                    print_codecs_for_id(desc->id, 1);
                    break;
    
    }
    
    static void print_codecs(int encoder)
    {
        const AVCodecDescriptor *desc = NULL;
    
        printf("%s:\n"
               " V... = Video\n"
               " A... = Audio\n"
               " S... = Subtitle\n"
               " .F.. = Frame-level multithreading\n"
               " ..S. = Slice-level multithreading\n"
               " ...X = Codec is experimental\n"
               " ---\n",
               encoder ? "Encoders" : "Decoders");
        while ((desc = avcodec_descriptor_next(desc))) {
            const AVCodec *codec = NULL;
    
            while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
                printf("%c", get_media_type_char(desc->type));
                printf((codec->capabilities & CODEC_CAP_FRAME_THREADS) ? "F" : ".");
                printf((codec->capabilities & CODEC_CAP_SLICE_THREADS) ? "S" : ".");
                printf((codec->capabilities & CODEC_CAP_EXPERIMENTAL)  ? "X" : ".");
    
                printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
                if (strcmp(codec->name, desc->name))
                    printf(" (codec %s)", desc->name);
    
                printf("\n");
            }
        }
    }
    
    
    int show_decoders(void *optctx, const char *opt, const char *arg)
    
    {
        print_codecs(0);
        return 0;
    }
    
    
    int show_encoders(void *optctx, const char *opt, const char *arg)
    
    {
        print_codecs(1);
        return 0;
    
    int show_bsfs(void *optctx, const char *opt, const char *arg)
    
        AVBitStreamFilter *bsf = NULL;
    
    
        printf("Bitstream filters:\n");
    
        while ((bsf = av_bitstream_filter_next(bsf)))
    
        printf("\n");
    
    int show_protocols(void *optctx, const char *opt, const char *arg)
    
        void *opaque = NULL;
        const char *name;
    
        printf("Supported file protocols:\n"
    
               "Input:\n");
        while ((name = avio_enum_protocols(&opaque, 0)))
            printf("%s\n", name);
        printf("Output:\n");
        while ((name = avio_enum_protocols(&opaque, 1)))
            printf("%s\n", name);
    
    int show_filters(void *optctx, const char *opt, const char *arg)
    
    #if CONFIG_AVFILTER
        const AVFilter *filter = NULL;
    
        while ((filter = avfilter_next(filter)))
            printf("%-16s %s\n", filter->name, filter->description);
    
    #else
        printf("No filters available: libavfilter disabled\n");
    
    int show_pix_fmts(void *optctx, const char *opt, const char *arg)
    
        const AVPixFmtDescriptor *pix_desc = NULL;
    
        printf("Pixel formats:\n"
               "I.... = Supported Input  format for conversion\n"
               ".O... = Supported Output format for conversion\n"
               "..H.. = Hardware accelerated format\n"
               "...P. = Paletted format\n"
               "....B = Bitstream format\n"
               "FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL\n"
               "-----\n");
    
    #if !CONFIG_SWSCALE
    #   define sws_isSupportedInput(x)  0
    #   define sws_isSupportedOutput(x) 0
    #endif
    
    
        while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
            enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
    
            printf("%c%c%c%c%c %-16s       %d            %2d\n",
    
                   sws_isSupportedInput (pix_fmt)              ? 'I' : '.',
                   sws_isSupportedOutput(pix_fmt)              ? 'O' : '.',
                   pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL   ? 'H' : '.',
                   pix_desc->flags & AV_PIX_FMT_FLAG_PAL       ? 'P' : '.',
                   pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.',
    
                   pix_desc->name,
                   pix_desc->nb_components,
                   av_get_bits_per_pixel(pix_desc));
        }
    
    int show_sample_fmts(void *optctx, const char *opt, const char *arg)
    
    {
        int i;
        char fmt_str[128];
        for (i = -1; i < AV_SAMPLE_FMT_NB; i++)
            printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i));
        return 0;
    }
    
    
    static void show_help_codec(const char *name, int encoder)
    {
        const AVCodecDescriptor *desc;
        const AVCodec *codec;
    
        if (!name) {
            av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n");
            return;
        }
    
        codec = encoder ? avcodec_find_encoder_by_name(name) :
                          avcodec_find_decoder_by_name(name);
    
        if (codec)
            print_codec(codec);
        else if ((desc = avcodec_descriptor_get_by_name(name))) {
            int printed = 0;
    
            while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
                printed = 1;
                print_codec(codec);
            }
    
            if (!printed) {
                av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to Libav, "
                       "but no %s for it are available. Libav might need to be "
                       "recompiled with additional external libraries.\n",
                       name, encoder ? "encoders" : "decoders");
            }
        } else {
            av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by Libav.\n",
                   name);
        }
    }
    
    
    static void show_help_demuxer(const char *name)
    {
        const AVInputFormat *fmt = av_find_input_format(name);
    
        if (!fmt) {
            av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
            return;
        }
    
        printf("Demuxer %s [%s]:\n", fmt->name, fmt->long_name);
    
        if (fmt->extensions)
            printf("    Common extensions: %s.\n", fmt->extensions);
    
        if (fmt->priv_class)
            show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM);
    }
    
    static void show_help_muxer(const char *name)
    {
        const AVCodecDescriptor *desc;
        const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL);
    
        if (!fmt) {
            av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
            return;
        }
    
        printf("Muxer %s [%s]:\n", fmt->name, fmt->long_name);
    
        if (fmt->extensions)
            printf("    Common extensions: %s.\n", fmt->extensions);
        if (fmt->mime_type)
            printf("    Mime type: %s.\n", fmt->mime_type);
        if (fmt->video_codec != AV_CODEC_ID_NONE &&
            (desc = avcodec_descriptor_get(fmt->video_codec))) {
            printf("    Default video codec: %s.\n", desc->name);
        }
        if (fmt->audio_codec != AV_CODEC_ID_NONE &&
            (desc = avcodec_descriptor_get(fmt->audio_codec))) {
            printf("    Default audio codec: %s.\n", desc->name);
        }
        if (fmt->subtitle_codec != AV_CODEC_ID_NONE &&
            (desc = avcodec_descriptor_get(fmt->subtitle_codec))) {
            printf("    Default subtitle codec: %s.\n", desc->name);
        }
    
        if (fmt->priv_class)
            show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM);
    }
    
    
    #if CONFIG_AVFILTER
    
    static void show_help_filter(const char *name)
    {
        const AVFilter *f = avfilter_get_by_name(name);
        int i, count;
    
        if (!name) {
            av_log(NULL, AV_LOG_ERROR, "No filter name specified.\n");
            return;
        } else if (!f) {
            av_log(NULL, AV_LOG_ERROR, "Unknown filter '%s'.\n", name);
            return;
        }
    
        printf("Filter %s [%s]:\n", f->name, f->description);
    
    
        if (f->flags & AVFILTER_FLAG_SLICE_THREADS)
            printf("    slice threading supported\n");
    
    
        printf("    Inputs:\n");
        count = avfilter_pad_count(f->inputs);
        for (i = 0; i < count; i++) {
            printf("        %d %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
                   media_type_string(avfilter_pad_get_type(f->inputs, i)));
        }
        if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)
            printf("        dynamic (depending on the options)\n");
    
        printf("    Outputs:\n");
        count = avfilter_pad_count(f->outputs);
        for (i = 0; i < count; i++) {
            printf("        %d %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
                   media_type_string(avfilter_pad_get_type(f->outputs, i)));
        }
        if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS)
            printf("        dynamic (depending on the options)\n");
    
        if (f->priv_class)
            show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM |
                                              AV_OPT_FLAG_AUDIO_PARAM);
    }
    
    int show_help(void *optctx, const char *opt, const char *arg)
    
    {
        char *topic, *par;
        av_log_set_callback(log_callback_help);
    
        topic = av_strdup(arg ? arg : "");
    
        if (!topic)
            return AVERROR(ENOMEM);
    
        par = strchr(topic, '=');
        if (par)
            *par++ = 0;
    
        if (!*topic) {
            show_help_default(topic, par);
        } else if (!strcmp(topic, "decoder")) {
            show_help_codec(par, 0);
        } else if (!strcmp(topic, "encoder")) {
            show_help_codec(par, 1);
    
        } else if (!strcmp(topic, "demuxer")) {
            show_help_demuxer(par);
        } else if (!strcmp(topic, "muxer")) {
            show_help_muxer(par);
    
    #if CONFIG_AVFILTER
    
        } else if (!strcmp(topic, "filter")) {
            show_help_filter(par);
    
        } else {
            show_help_default(topic, par);
        }
    
        av_freep(&topic);
        return 0;
    }
    
    
    int read_yesno(void)
    {
        int c = getchar();
    
        int yesno = (av_toupper(c) == 'Y');
    
    
        while (c != '\n' && c != EOF)
            c = getchar();
    
        return yesno;
    }
    
    int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
    
        FILE *f = fopen(filename, "rb");
    
            av_log(NULL, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename,
                   strerror(errno));
    
    
        ret = fseek(f, 0, SEEK_END);
        if (ret == -1) {
            ret = AVERROR(errno);
            goto out;
        }
    
        ret = ftell(f);
        if (ret < 0) {
            ret = AVERROR(errno);
            goto out;
        }
        *size = ret;
    
        ret = fseek(f, 0, SEEK_SET);
        if (ret == -1) {
            ret = AVERROR(errno);
            goto out;
        }
    
    
        *bufptr = av_malloc(*size + 1);
        if (!*bufptr) {
    
            av_log(NULL, AV_LOG_ERROR, "Could not allocate file buffer\n");
    
            ret = AVERROR(ENOMEM);
            goto out;
    
        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;
    
        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)
    
    FILE *get_preset_file(char *filename, size_t filename_size,
    
                          const char *preset_name, int is_path,
                          const char *codec_name)
    
        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);
    
    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;
    
            }
            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;
    
    Luca Barbato's avatar
    Luca Barbato committed
        } else if (*spec == 'i' && *(spec + 1) == ':') {
            int stream_id;
            char *endptr;
            spec += 2;
            stream_id = strtol(spec, &endptr, 0);
            return stream_id == st->id;
    
        } else if (*spec == 'm' && *(spec + 1) == ':') {
            AVDictionaryEntry *tag;
            char *key, *val;
            int ret;
    
            spec += 2;
            val = strchr(spec, ':');
    
            key = val ? av_strndup(spec, val - spec) : av_strdup(spec);
            if (!key)
                return AVERROR(ENOMEM);
    
            tag = av_dict_get(st->metadata, key, NULL, 0);
            if (tag) {
                if (!val || !strcmp(tag->value, val + 1))
                    ret = 1;
                else
                    ret = 0;
            } else
                ret = 0;
    
            av_freep(&key);
            return ret;
    
        } else if (*spec == 'u') {
            AVCodecContext *avctx = st->codec;
            int val;
            switch (avctx->codec_type) {
            case AVMEDIA_TYPE_AUDIO:
                val = avctx->sample_rate && avctx->channels;
                if (avctx->sample_fmt == AV_SAMPLE_FMT_NONE)
                    return 0;
                break;
            case AVMEDIA_TYPE_VIDEO:
                val = avctx->width && avctx->height;
                if (avctx->pix_fmt == AV_PIX_FMT_NONE)
                    return 0;
                break;
            case AVMEDIA_TYPE_UNKNOWN:
                val = 0;
                break;
            default:
                val = 1;
                break;
            }
            return avctx->codec_id != AV_CODEC_ID_NONE && val != 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;
    
        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;
    
        }
    
        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);
    
    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,
    
    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_program(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_program(1);
    
            }
            memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
            *size = new_size;
            return tmp;
        }
        return array;
    }
    
    
    const char *media_type_string(enum AVMediaType media_type)
    {
        switch (media_type) {
        case AVMEDIA_TYPE_VIDEO:      return "video";
        case AVMEDIA_TYPE_AUDIO:      return "audio";
        case AVMEDIA_TYPE_DATA:       return "data";
        case AVMEDIA_TYPE_SUBTITLE:   return "subtitle";
        case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
        default:                      return "unknown";
        }
    }