diff options
author | Peter Ross <pross@xvid.org> | 2012-11-07 16:52:33 +1100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-11-07 13:59:03 +0100 |
commit | a373f352728c5f56b6679ea8ab668d830811c324 (patch) | |
tree | a08d0b29d6f2f5b316d5a81ffaa82c6322c1a0e5 /libavformat/wtvenc.c | |
parent | b89cd2a0289fc667d21c8e0f693722ca068ed52b (diff) | |
download | ffmpeg-a373f352728c5f56b6679ea8ab668d830811c324.tar.gz |
wtvenc: produce seekable files
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/wtvenc.c')
-rw-r--r-- | libavformat/wtvenc.c | 78 |
1 files changed, 71 insertions, 7 deletions
diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c index 9108bc0013..9cc5a05708 100644 --- a/libavformat/wtvenc.c +++ b/libavformat/wtvenc.c @@ -80,17 +80,43 @@ typedef struct { } WtvChunkEntry; typedef struct { + int64_t serial; + int64_t value; +} WtvSyncEntry; + +typedef struct { int64_t timeline_start_pos; WtvFile file[WTV_FILES]; int64_t serial; /** chunk serial number */ int64_t last_chunk_pos; /** last chunk position */ + int64_t last_timestamp_pos; /** last timestamp chunk position */ + int64_t first_index_pos; /** first index_chunk position */ WtvChunkEntry index[MAX_NB_INDEX]; int nb_index; int first_video_flag; - int64_t sync_pos; + + WtvSyncEntry *st_pairs; /* (serial, timestamp) pairs */ + int nb_st_pairs; + WtvSyncEntry *sp_pairs; /* (serial, position) pairs */ + int nb_sp_pairs; + + int64_t last_pts; + int64_t last_serial; } WtvContext; + +static void add_serial_pair(WtvSyncEntry ** list, int * count, int64_t serial, int64_t value) +{ + int new_count = *count + 1; + WtvSyncEntry *new_list = av_realloc(*list, new_count * sizeof(WtvSyncEntry)); + if (!new_list) + return; + new_list[*count] = (WtvSyncEntry){serial, value}; + *list = new_list; + *count = new_count; +} + typedef int WTVHeaderWriteFunc(AVIOContext *pb); typedef struct { @@ -186,6 +212,9 @@ static void write_index(AVFormatContext *s) } wctx->nb_index = 0; // reset index finish_chunk_noindex(s); + + if (!wctx->first_index_pos) + wctx->first_index_pos = wctx->last_chunk_pos; } static void finish_chunk(AVFormatContext *s) @@ -277,12 +306,14 @@ static void write_sync(AVFormatContext *s) AVIOContext *pb = s->pb; WtvContext *wctx = s->priv_data; int64_t last_chunk_pos = wctx->last_chunk_pos; - wctx->sync_pos = avio_tell(pb) - wctx->timeline_start_pos; write_chunk_header(s, &ff_sync_guid, 0x18, 0); - write_pad(pb, 24); + avio_wl64(pb, wctx->first_index_pos); + avio_wl64(pb, wctx->last_timestamp_pos); + avio_wl64(pb, 0); finish_chunk(s); + add_serial_pair(&wctx->sp_pairs, &wctx->nb_sp_pairs, wctx->serial, wctx->last_chunk_pos); wctx->last_chunk_pos = last_chunk_pos; } @@ -317,6 +348,9 @@ static int write_header(AVFormatContext *s) int i, pad, ret; AVStream *st; + wctx->last_chunk_pos = -1; + wctx->last_timestamp_pos = -1; + ff_put_guid(pb, &ff_wtv_guid); ff_put_guid(pb, &sub_wtv_guid); @@ -335,6 +369,7 @@ static int write_header(AVFormatContext *s) pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb); write_pad(pb, pad); + wctx->timeline_start_pos = avio_tell(pb); wctx->serial = 1; @@ -381,6 +416,8 @@ static void write_timestamp(AVFormatContext *s, AVPacket *pkt) avio_wl64(pb, 0); avio_wl64(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0); avio_wl64(pb, 0); + + wctx->last_timestamp_pos = wctx->last_chunk_pos; } static int write_packet(AVFormatContext *s, AVPacket *pkt) @@ -388,6 +425,19 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) AVIOContext *pb = s->pb; WtvContext *wctx = s->priv_data; + /* 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); + + /* emit 'table.0.entries.time' record every 500ms */ + if (pkt->pts != AV_NOPTS_VALUE && pkt->pts - (wctx->nb_st_pairs ? wctx->st_pairs[wctx->nb_st_pairs - 1].value : 0) >= 5000000) + add_serial_pair(&wctx->st_pairs, &wctx->nb_st_pairs, wctx->serial, pkt->pts); + + if (pkt->pts != AV_NOPTS_VALUE && pkt->pts > wctx->last_pts) { + wctx->last_pts = pkt->pts; + wctx->last_serial = wctx->serial; + } + // write timestamp chunk write_timestamp(s, pkt); @@ -520,10 +570,24 @@ static void write_table_entries_events(AVFormatContext *s) { AVIOContext *pb = s->pb; WtvContext *wctx = s->priv_data; + int i; + for (i = 0; i < wctx->nb_sp_pairs; i++) { + avio_wl64(pb, wctx->sp_pairs[i].serial); + avio_wl64(pb, wctx->sp_pairs[i].value); + } +} - //FIXME: output frame_nb, position pairs. - //We only set the first sync_chunk position here. - avio_wl64(pb, 0x2); avio_wl64(pb, wctx->sync_pos); +static void write_table_entries_time(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + int i; + for (i = 0; i < wctx->nb_st_pairs; i++) { + avio_wl64(pb, wctx->st_pairs[i].value); + avio_wl64(pb, wctx->st_pairs[i].serial); + } + avio_wl64(pb, wctx->last_pts); + avio_wl64(pb, wctx->last_serial); } static void write_tag(AVIOContext *pb, const char *key, const char *value) @@ -648,7 +712,7 @@ static int write_trailer(AVFormatContext *s) return -1; start_pos = avio_tell(pb); - //FIXME: output timestamp, frame_nb pairs here. + write_table_entries_time(s); if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0) return -1; |