matroskaenc: implement CueRelativePosition

This is a minimal change to matroskaenc that implements CueRelativePosition in the output.
Most players will probably ignore this additional information, but it is in the
matroska spec, and it'd be nice to be able to make use of it.

Signed-off-by: Bernt Habermeier <bernt@wulfram.com>
Tested-by:  wm4 <nfxjfg@googlemail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
pull/37/head
Bernie Habermeier 11 years ago committed by Michael Niedermayer
parent 101c7ea906
commit c5f3cc40e3
  1. 1
      libavformat/matroska.h
  2. 20
      libavformat/matroskaenc.c
  3. 8
      tests/ref/lavf/mkv

@ -156,6 +156,7 @@
/* IDs in the cuetrackposition master */ /* IDs in the cuetrackposition master */
#define MATROSKA_ID_CUETRACK 0xF7 #define MATROSKA_ID_CUETRACK 0xF7
#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 #define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
#define MATROSKA_ID_CUERELATIVEPOSITION 0xF0
#define MATROSKA_ID_CUEBLOCKNUMBER 0x5378 #define MATROSKA_ID_CUEBLOCKNUMBER 0x5378
/* IDs in the tags master */ /* IDs in the tags master */

@ -67,6 +67,7 @@ typedef struct {
uint64_t pts; uint64_t pts;
int tracknum; int tracknum;
int64_t cluster_pos; ///< file offset of the cluster containing the block int64_t cluster_pos; ///< file offset of the cluster containing the block
int64_t relative_pos; ///< relative offset from the position of the cluster containing the block
} mkv_cuepoint; } mkv_cuepoint;
typedef struct { typedef struct {
@ -113,9 +114,9 @@ typedef struct MatroskaMuxContext {
* offset, 4 bytes for target EBML ID */ * offset, 4 bytes for target EBML ID */
#define MAX_SEEKENTRY_SIZE 21 #define MAX_SEEKENTRY_SIZE 21
/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2 /** per-cuepoint-track - 4 1-byte EBML IDs, 4 1-byte EBML sizes, 3
* 8-byte uint max */ * 8-byte uint max */
#define MAX_CUETRACKPOS_SIZE 22 #define MAX_CUETRACKPOS_SIZE 32
/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */ /** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */
#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks #define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks
@ -372,7 +373,7 @@ static mkv_cues * mkv_start_cues(int64_t segment_offset)
return cues; return cues;
} }
static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos) static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos, int64_t relative_pos)
{ {
mkv_cuepoint *entries = cues->entries; mkv_cuepoint *entries = cues->entries;
@ -385,7 +386,8 @@ static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t clus
entries[cues->num_entries ].pts = ts; entries[cues->num_entries ].pts = ts;
entries[cues->num_entries ].tracknum = stream + 1; entries[cues->num_entries ].tracknum = stream + 1;
entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset; entries[cues->num_entries ].cluster_pos = cluster_pos - cues->segment_offset;
entries[cues->num_entries++].relative_pos = relative_pos;
cues->entries = entries; cues->entries = entries;
return 0; return 0;
@ -419,8 +421,9 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, mkv_track *tracks
continue; continue;
tracks[tracknum].has_cue = 1; tracks[tracknum].has_cue = 1;
track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE); track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);
put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum ); put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos); put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION , entry[j].cluster_pos);
put_ebml_uint(pb, MATROSKA_ID_CUERELATIVEPOSITION, entry[j].relative_pos);
end_ebml_master(pb, track_positions); end_ebml_master(pb, track_positions);
} }
i += j - 1; i += j - 1;
@ -1414,6 +1417,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
int duration = pkt->duration; int duration = pkt->duration;
int ret; int ret;
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
int64_t relative_packet_pos;
if (ts == AV_NOPTS_VALUE) { if (ts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n"); av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n");
@ -1437,6 +1441,8 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
mkv->cluster_pts = FFMAX(0, ts); mkv->cluster_pts = FFMAX(0, ts);
} }
relative_packet_pos = avio_tell(s->pb) - mkv->cluster.pos;
if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) { if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7); mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7);
#if FF_API_ASS_SSA #if FF_API_ASS_SSA
@ -1459,7 +1465,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
} }
if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) { if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) {
ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos); ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos);
if (ret < 0) return ret; if (ret < 0) return ret;
} }

@ -1,6 +1,6 @@
1748c0b3221977509c62a158236d2492 *./tests/data/lavf/lavf.mkv b9557a7fa418db7692587b45d20f0d76 *./tests/data/lavf/lavf.mkv
472533 ./tests/data/lavf/lavf.mkv 472542 ./tests/data/lavf/lavf.mkv
./tests/data/lavf/lavf.mkv CRC=0x4780846b ./tests/data/lavf/lavf.mkv CRC=0x4780846b
0f78dd9299210a51b18faafc971e71f2 *./tests/data/lavf/lavf.mkv fd214bc74f0a21dfb36dcf9bb5777b86 *./tests/data/lavf/lavf.mkv
320265 ./tests/data/lavf/lavf.mkv 320274 ./tests/data/lavf/lavf.mkv
./tests/data/lavf/lavf.mkv CRC=0x4780846b ./tests/data/lavf/lavf.mkv CRC=0x4780846b

Loading…
Cancel
Save