diff --git a/ffmpeg.c b/ffmpeg.c index 97526cbceb..a4800685eb 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2776,6 +2776,7 @@ static void opt_input_file(const char *filename) if(subtitle_disable) ic->streams[i]->discard = AVDISCARD_ALL; break; + case CODEC_TYPE_ATTACHMENT: case CODEC_TYPE_UNKNOWN: break; default: @@ -2825,6 +2826,7 @@ static void check_audio_video_sub_inputs(int *has_video_ptr, int *has_audio_ptr, has_subtitle = 1; break; case CODEC_TYPE_DATA: + case CODEC_TYPE_ATTACHMENT: case CODEC_TYPE_UNKNOWN: break; default: diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index bcf9fb6467..f8c81783aa 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -33,8 +33,8 @@ #define AV_STRINGIFY(s) AV_TOSTRING(s) #define AV_TOSTRING(s) #s -#define LIBAVCODEC_VERSION_INT ((51<<16)+(49<<8)+0) -#define LIBAVCODEC_VERSION 51.49.0 +#define LIBAVCODEC_VERSION_INT ((51<<16)+(50<<8)+0) +#define LIBAVCODEC_VERSION 51.50.0 #define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) @@ -284,6 +284,9 @@ enum CodecID { CODEC_ID_XSUB, CODEC_ID_SSA, + /* other specific kind of codecs (generaly used for attachments) */ + CODEC_ID_TTF= 0x18000, + CODEC_ID_MPEG2TS= 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS * stream (only used by libavformat) */ }; @@ -300,6 +303,7 @@ enum CodecType { CODEC_TYPE_AUDIO, CODEC_TYPE_DATA, CODEC_TYPE_SUBTITLE, + CODEC_TYPE_ATTACHMENT, CODEC_TYPE_NB }; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 4a8cb8a603..4ebc7c324b 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -1219,6 +1219,10 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) snprintf(buf, buf_size, "Subtitle: %s", codec_name); bitrate = enc->bit_rate; break; + case CODEC_TYPE_ATTACHMENT: + snprintf(buf, buf_size, "Attachment: %s", codec_name); + bitrate = enc->bit_rate; + break; default: snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type); return; diff --git a/libavformat/avformat.h b/libavformat/avformat.h index cb6024500f..ddebb7714e 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -21,8 +21,8 @@ #ifndef FFMPEG_AVFORMAT_H #define FFMPEG_AVFORMAT_H -#define LIBAVFORMAT_VERSION_INT ((52<<16)+(5<<8)+0) -#define LIBAVFORMAT_VERSION 52.5.0 +#define LIBAVFORMAT_VERSION_INT ((52<<16)+(6<<8)+0) +#define LIBAVFORMAT_VERSION 52.6.0 #define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) @@ -347,6 +347,8 @@ typedef struct AVStream { #define MAX_REORDER_DELAY 4 int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + char *filename; /**< source filename of the stream */ } AVStream; #define AV_PROGRAM_RUNNING 1 diff --git a/libavformat/matroska.c b/libavformat/matroska.c index 382534e9bd..b62511f29f 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -71,3 +71,15 @@ const CodecTags ff_mkv_codec_tags[]={ {"" , CODEC_ID_NONE} /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ }; + +const CodecMime ff_mkv_mime_tags[] = { + {"text/plain" , CODEC_ID_TEXT}, + {"image/gif" , CODEC_ID_GIF}, + {"image/jpeg" , CODEC_ID_MJPEG}, + {"image/png" , CODEC_ID_PNG}, + {"image/tiff" , CODEC_ID_TIFF}, + {"application/x-truetype-font", CODEC_ID_TTF}, + {"application/x-font" , CODEC_ID_TTF}, + + {"" , CODEC_ID_NONE} +}; diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 43fbb9e9c5..370a8bfd89 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -55,6 +55,7 @@ #define MATROSKA_ID_CUES 0x1C53BB6B #define MATROSKA_ID_TAGS 0x1254C367 #define MATROSKA_ID_SEEKHEAD 0x114D9B74 +#define MATROSKA_ID_ATTACHMENTS 0x1941A469 #define MATROSKA_ID_CLUSTER 0x1F43B675 /* IDs in the info master */ @@ -138,6 +139,13 @@ #define MATROSKA_ID_BLOCKDURATION 0x9B #define MATROSKA_ID_BLOCKREFERENCE 0xFB +/* IDs in the attachments master */ +#define MATROSKA_ID_ATTACHEDFILE 0x61A7 +#define MATROSKA_ID_FILENAME 0x466E +#define MATROSKA_ID_FILEMIMETYPE 0x4660 +#define MATROSKA_ID_FILEDATA 0x465C +#define MATROSKA_ID_FILEUID 0x46AE + typedef enum { MATROSKA_TRACK_TYPE_VIDEO = 0x1, MATROSKA_TRACK_TYPE_AUDIO = 0x2, @@ -185,6 +193,11 @@ typedef struct CodecTags{ enum CodecID id; }CodecTags; +typedef struct CodecMime{ + char str[32]; + enum CodecID id; +}CodecMime; + #define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" @@ -192,5 +205,6 @@ typedef struct CodecTags{ #define EBML_MAX_DEPTH 16 extern const CodecTags ff_mkv_codec_tags[]; +extern const CodecMime ff_mkv_mime_tags[]; #endif /* FFMPEG_MATROSKA_H */ diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index cc45e9599c..d96b36edf8 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1865,6 +1865,119 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) return res; } +static int +matroska_parse_attachments(AVFormatContext *s) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing attachments...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_ATTACHEDFILE: { + char* name = NULL; + char* mime = NULL; + uint8_t* data = NULL; + int i, data_size = 0; + AVStream *st; + + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_FILENAME: + res = ebml_read_utf8 (matroska, &id, &name); + break; + + case MATROSKA_ID_FILEMIMETYPE: + res = ebml_read_ascii (matroska, &id, &mime); + break; + + case MATROSKA_ID_FILEDATA: + res = ebml_read_binary(matroska, &id, &data, &data_size); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown attachedfile ID 0x%x\n", id); + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (!(name && mime && data && data_size > 0)) { + av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n"); + break; + } + + st = av_new_stream(s, matroska->num_streams++); + if (st == NULL) + return AVERROR(ENOMEM); + st->filename = av_strdup(name); + st->codec->codec_id = CODEC_ID_NONE; + st->codec->codec_type = CODEC_TYPE_ATTACHMENT; + st->codec->extradata = av_malloc(data_size); + if(st->codec->extradata == NULL) + return AVERROR(ENOMEM); + st->codec->extradata_size = data_size; + memcpy(st->codec->extradata, data, data_size); + + for (i=0; ff_mkv_mime_tags[i].id != CODEC_ID_NONE; i++) { + if (!strncmp(ff_mkv_mime_tags[i].str, mime, + strlen(ff_mkv_mime_tags[i].str))) { + st->codec->codec_id = ff_mkv_mime_tags[i].id; + break; + } + } + + av_log(matroska->ctx, AV_LOG_DEBUG, "new attachment: %s, %s, size %d \n", name, mime, data_size); + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown attachments ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) static int @@ -2007,6 +2120,13 @@ matroska_read_header (AVFormatContext *s, break; } + case MATROSKA_ID_ATTACHMENTS: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_attachments(s); + break; + } + case MATROSKA_ID_CLUSTER: { /* Do not read the master - this will be done in the next * call to matroska_read_packet. */ diff --git a/libavformat/utils.c b/libavformat/utils.c index d3e6afef57..ffb2d84818 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2112,6 +2112,7 @@ void av_close_input_stream(AVFormatContext *s) av_free(st->index_entries); av_free(st->codec->extradata); av_free(st->codec); + av_free(st->filename); av_free(st); } for(i=s->nb_programs-1; i>=0; i--) {