patch by eugeni _dot_ stepanov _at_ gmail.com and myself Originally committed as revision 11635 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -2776,6 +2776,7 @@ static void opt_input_file(const char *filename) | |||||
| if(subtitle_disable) | if(subtitle_disable) | ||||
| ic->streams[i]->discard = AVDISCARD_ALL; | ic->streams[i]->discard = AVDISCARD_ALL; | ||||
| break; | break; | ||||
| case CODEC_TYPE_ATTACHMENT: | |||||
| case CODEC_TYPE_UNKNOWN: | case CODEC_TYPE_UNKNOWN: | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -2825,6 +2826,7 @@ static void check_audio_video_sub_inputs(int *has_video_ptr, int *has_audio_ptr, | |||||
| has_subtitle = 1; | has_subtitle = 1; | ||||
| break; | break; | ||||
| case CODEC_TYPE_DATA: | case CODEC_TYPE_DATA: | ||||
| case CODEC_TYPE_ATTACHMENT: | |||||
| case CODEC_TYPE_UNKNOWN: | case CODEC_TYPE_UNKNOWN: | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -33,8 +33,8 @@ | |||||
| #define AV_STRINGIFY(s) AV_TOSTRING(s) | #define AV_STRINGIFY(s) AV_TOSTRING(s) | ||||
| #define AV_TOSTRING(s) #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_BUILD LIBAVCODEC_VERSION_INT | ||||
| #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) | #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) | ||||
| @@ -284,6 +284,9 @@ enum CodecID { | |||||
| CODEC_ID_XSUB, | CODEC_ID_XSUB, | ||||
| CODEC_ID_SSA, | 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 | CODEC_ID_MPEG2TS= 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS | ||||
| * stream (only used by libavformat) */ | * stream (only used by libavformat) */ | ||||
| }; | }; | ||||
| @@ -300,6 +303,7 @@ enum CodecType { | |||||
| CODEC_TYPE_AUDIO, | CODEC_TYPE_AUDIO, | ||||
| CODEC_TYPE_DATA, | CODEC_TYPE_DATA, | ||||
| CODEC_TYPE_SUBTITLE, | CODEC_TYPE_SUBTITLE, | ||||
| CODEC_TYPE_ATTACHMENT, | |||||
| CODEC_TYPE_NB | CODEC_TYPE_NB | ||||
| }; | }; | ||||
| @@ -1219,6 +1219,10 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) | |||||
| snprintf(buf, buf_size, "Subtitle: %s", codec_name); | snprintf(buf, buf_size, "Subtitle: %s", codec_name); | ||||
| bitrate = enc->bit_rate; | bitrate = enc->bit_rate; | ||||
| break; | break; | ||||
| case CODEC_TYPE_ATTACHMENT: | |||||
| snprintf(buf, buf_size, "Attachment: %s", codec_name); | |||||
| bitrate = enc->bit_rate; | |||||
| break; | |||||
| default: | default: | ||||
| snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type); | snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type); | ||||
| return; | return; | ||||
| @@ -21,8 +21,8 @@ | |||||
| #ifndef FFMPEG_AVFORMAT_H | #ifndef FFMPEG_AVFORMAT_H | ||||
| #define 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_BUILD LIBAVFORMAT_VERSION_INT | ||||
| #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) | #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) | ||||
| @@ -347,6 +347,8 @@ typedef struct AVStream { | |||||
| #define MAX_REORDER_DELAY 4 | #define MAX_REORDER_DELAY 4 | ||||
| int64_t pts_buffer[MAX_REORDER_DELAY+1]; | int64_t pts_buffer[MAX_REORDER_DELAY+1]; | ||||
| char *filename; /**< source filename of the stream */ | |||||
| } AVStream; | } AVStream; | ||||
| #define AV_PROGRAM_RUNNING 1 | #define AV_PROGRAM_RUNNING 1 | ||||
| @@ -71,3 +71,15 @@ const CodecTags ff_mkv_codec_tags[]={ | |||||
| {"" , CODEC_ID_NONE} | {"" , CODEC_ID_NONE} | ||||
| /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ | /* 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} | |||||
| }; | |||||
| @@ -55,6 +55,7 @@ | |||||
| #define MATROSKA_ID_CUES 0x1C53BB6B | #define MATROSKA_ID_CUES 0x1C53BB6B | ||||
| #define MATROSKA_ID_TAGS 0x1254C367 | #define MATROSKA_ID_TAGS 0x1254C367 | ||||
| #define MATROSKA_ID_SEEKHEAD 0x114D9B74 | #define MATROSKA_ID_SEEKHEAD 0x114D9B74 | ||||
| #define MATROSKA_ID_ATTACHMENTS 0x1941A469 | |||||
| #define MATROSKA_ID_CLUSTER 0x1F43B675 | #define MATROSKA_ID_CLUSTER 0x1F43B675 | ||||
| /* IDs in the info master */ | /* IDs in the info master */ | ||||
| @@ -138,6 +139,13 @@ | |||||
| #define MATROSKA_ID_BLOCKDURATION 0x9B | #define MATROSKA_ID_BLOCKDURATION 0x9B | ||||
| #define MATROSKA_ID_BLOCKREFERENCE 0xFB | #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 { | typedef enum { | ||||
| MATROSKA_TRACK_TYPE_VIDEO = 0x1, | MATROSKA_TRACK_TYPE_VIDEO = 0x1, | ||||
| MATROSKA_TRACK_TYPE_AUDIO = 0x2, | MATROSKA_TRACK_TYPE_AUDIO = 0x2, | ||||
| @@ -185,6 +193,11 @@ typedef struct CodecTags{ | |||||
| enum CodecID id; | enum CodecID id; | ||||
| }CodecTags; | }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_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" | ||||
| #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" | #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" | ||||
| @@ -192,5 +205,6 @@ typedef struct CodecTags{ | |||||
| #define EBML_MAX_DEPTH 16 | #define EBML_MAX_DEPTH 16 | ||||
| extern const CodecTags ff_mkv_codec_tags[]; | extern const CodecTags ff_mkv_codec_tags[]; | ||||
| extern const CodecMime ff_mkv_mime_tags[]; | |||||
| #endif /* FFMPEG_MATROSKA_H */ | #endif /* FFMPEG_MATROSKA_H */ | ||||
| @@ -1865,6 +1865,119 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska) | |||||
| return res; | 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)) | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) | ||||
| static int | static int | ||||
| @@ -2007,6 +2120,13 @@ matroska_read_header (AVFormatContext *s, | |||||
| break; | break; | ||||
| } | } | ||||
| case MATROSKA_ID_ATTACHMENTS: { | |||||
| if ((res = ebml_read_master(matroska, &id)) < 0) | |||||
| break; | |||||
| res = matroska_parse_attachments(s); | |||||
| break; | |||||
| } | |||||
| case MATROSKA_ID_CLUSTER: { | case MATROSKA_ID_CLUSTER: { | ||||
| /* Do not read the master - this will be done in the next | /* Do not read the master - this will be done in the next | ||||
| * call to matroska_read_packet. */ | * call to matroska_read_packet. */ | ||||
| @@ -2112,6 +2112,7 @@ void av_close_input_stream(AVFormatContext *s) | |||||
| av_free(st->index_entries); | av_free(st->index_entries); | ||||
| av_free(st->codec->extradata); | av_free(st->codec->extradata); | ||||
| av_free(st->codec); | av_free(st->codec); | ||||
| av_free(st->filename); | |||||
| av_free(st); | av_free(st); | ||||
| } | } | ||||
| for(i=s->nb_programs-1; i>=0; i--) { | for(i=s->nb_programs-1; i>=0; i--) { | ||||