[FFmpeg-cvslog] wtvenc: mux thumbnail picture
Peter Ross
git at videolan.org
Mon Jan 7 13:16:20 CET 2013
ffmpeg | branch: master | Peter Ross <pross at xvid.org> | Sun Jan 6 14:15:25 2013 +1100| [801b636633ea80e15af4f22d148b2981f573d739] | committer: Peter Ross
wtvenc: mux thumbnail picture
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=801b636633ea80e15af4f22d148b2981f573d739
---
libavformat/wtvenc.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 65 insertions(+), 5 deletions(-)
diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c
index 304bd14..22917a4 100644
--- a/libavformat/wtvenc.c
+++ b/libavformat/wtvenc.c
@@ -103,6 +103,8 @@ typedef struct {
int64_t last_pts;
int64_t last_serial;
+
+ AVPacket thumbnail;
} WtvContext;
@@ -378,6 +380,8 @@ static int write_header(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
+ continue;
ret = write_stream_codec(s, st);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
@@ -389,6 +393,8 @@ static int write_header(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
+ continue;
ret = write_stream_data(s, st);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
@@ -425,6 +431,11 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
WtvContext *wctx = s->priv_data;
+ if (s->streams[pkt->stream_index]->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) {
+ av_copy_packet(&wctx->thumbnail, pkt);
+ return 0;
+ }
+
/* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */
if (wctx->serial - (wctx->nb_sp_pairs ? wctx->sp_pairs[wctx->nb_sp_pairs - 1].serial : 0) >= 50)
write_sync(s);
@@ -590,27 +601,66 @@ static void write_table_entries_time(AVFormatContext *s)
avio_wl64(pb, wctx->last_serial);
}
-static void write_tag(AVIOContext *pb, const char *key, const char *value)
+static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
{
ff_put_guid(pb, &ff_metadata_guid);
- avio_wl32(pb, 1);
- avio_wl32(pb, strlen(value)*2 + 2);
+ avio_wl32(pb, type);
+ avio_wl32(pb, value_size);
avio_put_str16le(pb, key);
+}
+
+static int metadata_header_size(const char *key)
+{
+ return 16 + 4 + 4 + strlen(key)*2 + 2;
+}
+
+static void write_tag_int32(AVIOContext *pb, const char *key, int value)
+{
+ write_metadata_header(pb, 0, key, 4);
+ avio_wl32(pb, value);
+}
+
+static void write_tag(AVIOContext *pb, const char *key, const char *value)
+{
+ write_metadata_header(pb, 1, key, strlen(value)*2 + 2);
avio_put_str16le(pb, value);
}
+static int attachment_value_size(const AVPacket *pkt, const AVDictionaryEntry *e)
+{
+ return strlen("image/jpeg")*2 + 2 + 1 + (e ? strlen(e->value)*2 : 0) + 2 + 4 + pkt->size;
+}
+
static void write_table_entries_attrib(AVFormatContext *s)
{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
AVDictionaryEntry *tag = 0;
//FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
- write_tag(s->pb, tag->key, tag->value);
+ write_tag(pb, tag->key, tag->value);
+
+ if (wctx->thumbnail.size) {
+ AVStream *st = s->streams[wctx->thumbnail.stream_index];
+ tag = av_dict_get(st->metadata, "title", NULL, 0);
+ write_metadata_header(pb, 2, "WM/Picture", attachment_value_size(&wctx->thumbnail, tag));
+
+ avio_put_str16le(pb, "image/jpeg");
+ avio_w8(pb, 0x10);
+ avio_put_str16le(pb, tag ? tag->value : "");
+
+ avio_wl32(pb, wctx->thumbnail.size);
+ avio_write(pb, wctx->thumbnail.data, wctx->thumbnail.size);
+
+ write_tag_int32(pb, "WM/MediaThumbType", 2);
+ }
}
static void write_table_redirector_legacy_attrib(AVFormatContext *s)
{
+ WtvContext *wctx = s->priv_data;
AVIOContext *pb = s->pb;
AVDictionaryEntry *tag = 0;
int64_t pos = 0;
@@ -618,7 +668,16 @@ static void write_table_redirector_legacy_attrib(AVFormatContext *s)
//FIXME: translate special tags to binary representation
while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
avio_wl64(pb, pos);
- pos += 16 + 4 + 4 + strlen(tag->key)*2 + 2 + strlen(tag->value)*2 + 2;
+ pos += metadata_header_size(tag->key) + strlen(tag->value)*2 + 2;
+ }
+
+ if (wctx->thumbnail.size) {
+ AVStream *st = s->streams[wctx->thumbnail.stream_index];
+ avio_wl64(pb, pos);
+ pos += metadata_header_size("WM/Picture") + attachment_value_size(&wctx->thumbnail, av_dict_get(st->metadata, "title", NULL, 0));
+
+ avio_wl64(pb, pos);
+ pos += metadata_header_size("WM/MediaThumbType") + 4;
}
}
@@ -732,6 +791,7 @@ static int write_trailer(AVFormatContext *s)
av_free(wctx->sp_pairs);
av_free(wctx->st_pairs);
+ av_free_packet(&wctx->thumbnail);
return 0;
}
More information about the ffmpeg-cvslog
mailing list