ref: c7c0c05608a883830e2e1a77796b2b66656d75d1
parent: 927f29a64495fecc244b1eec760f9d2b24d952ad
author: John Koleszar <jkoleszar@google.com>
date: Wed Oct 27 06:05:55 EDT 2010
vpxenc: add unique track id MKV requires a unique(ish) TrackID element in the track info header. Instead of the current hard-coded ID, take a hash of the video track and use that. This value is not written in the deterministic output mode, despite being a deterministic value itself, to give flexibility to change the hash algorithm and not affect bisecting across the change. Change-Id: I807fc3ea6d1427a151c3ef703269b67e80aef860
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -444,6 +444,9 @@
off_t cue_pos;
off_t cluster_pos;
+ /* This pointer is to a specific element to be serialized */
+ off_t track_id_pos;
+
/* These pointers are to the size field of the element */
EbmlLoc startSegment;
EbmlLoc startCluster;
@@ -472,6 +475,18 @@
}
+/* Need a fixed size serializer for the track ID. libmkv provdes a 64 bit
+ * one, but not a 32 bit one.
+ */
+static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint64_t ui)
+{
+ unsigned char sizeSerialized = 4 | 0x80;
+ Ebml_WriteID(glob, class_id);
+ Ebml_Serialize(glob, &sizeSerialized, 1);
+ Ebml_Serialize(glob, &ui, 4);
+}
+
+
static void
Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc,
unsigned long class_id)
@@ -597,7 +612,8 @@
EbmlLoc start;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- Ebml_SerializeUnsigned(glob, TrackUID, trackID);
+ glob->track_id_pos = ftello(glob->stream);
+ Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1
Ebml_SerializeString(glob, CodecID, "V_VP8");
{
@@ -699,7 +715,7 @@
static void
-write_webm_file_footer(EbmlGlobal *glob)
+write_webm_file_footer(EbmlGlobal *glob, long hash)
{
if(glob->cluster_open)
@@ -738,10 +754,63 @@
/* Patch up the seek info block */
write_webm_seek_info(glob);
+
+ /* Patch up the track id */
+ fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
+ Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
+
fseeko(glob->stream, 0, SEEK_END);
}
+/* Murmur hash derived from public domain reference implementation at
+ * http://sites.google.com/site/murmurhash/
+ */
+static unsigned int murmur ( const void * key, int len, unsigned int seed )
+{
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ unsigned int h = seed ^ len;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ unsigned int k;
+
+ k = data[0];
+ k |= data[1] << 8;
+ k |= data[2] << 16;
+ k |= data[3] << 24;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+
#include "args.h"
static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
@@ -979,6 +1048,7 @@
int arg_have_framerate = 0;
int write_webm = 1;
EbmlGlobal ebml = {0};
+ uint32_t hash = 0;
exec_name = argv_[0];
@@ -1468,8 +1538,14 @@
frames_out++;
fprintf(stderr, " %6luF",
(unsigned long)pkt->data.frame.sz);
+
if(write_webm)
{
+ /* Update the hash */
+ if(!ebml.debug)
+ hash = murmur(pkt->data.frame.buf,
+ pkt->data.frame.sz, hash);
+
write_webm_block(&ebml, &cfg, pkt);
}
else
@@ -1522,7 +1598,7 @@
if(write_webm)
{
- write_webm_file_footer(&ebml);
+ write_webm_file_footer(&ebml, hash);
}
else
{