Add support for Matroska attachments.
patch by eugeni _dot_ stepanov _at_ gmail.com and myself Originally committed as revision 11635 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
20963a7156
commit
f8d7c9d373
2
ffmpeg.c
2
ffmpeg.c
@ -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_INT ((51<<16)+(50<<8)+0)
|
||||||
#define LIBAVCODEC_VERSION 51.49.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_INT ((52<<16)+(6<<8)+0)
|
||||||
#define LIBAVFORMAT_VERSION 52.5.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--) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user