Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(750)

Unified Diff: media/filters/webm_parser.cc

Issue 7203002: Adding ChunkDemuxer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More cleanup & commenting Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/filters/webm_parser.cc
diff --git a/media/filters/webm_parser.cc b/media/filters/webm_parser.cc
new file mode 100644
index 0000000000000000000000000000000000000000..49308e2d92ef47813937688b4726d4334638af66
--- /dev/null
+++ b/media/filters/webm_parser.cc
@@ -0,0 +1,394 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/filters/webm_parser.h"
+
scherkus (not reviewing) 2011/06/22 17:31:09 I believe you're doing ebml parsing here, so how a
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+#include <iomanip>
+
+#include "base/logging.h"
+
+namespace media {
+
+static const int kMaxLevelDepth = 6;
scherkus (not reviewing) 2011/06/22 17:31:09 docs?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+
+WebMParserClient::~WebMParserClient() {}
scherkus (not reviewing) 2011/06/22 17:31:09 you can actually inline this in the .h if you want
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 If I remember correctly there was this pass over a
+
+int webm_parse_num(const uint8* buf, int size, int max_bytes,
scherkus (not reviewing) 2011/06/22 17:31:09 docs? I don't think we need to document the bit-t
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ bool mask_first_byte, int64* num) {
+ DCHECK(buf);
+ DCHECK(num);
+
+ if (size <= 0)
+ return -1;
+
+ int mask = 0x80;
+ uint8 ch = buf[0];
+ int extra_bytes = -1;
+ for (int i = 0; i < max_bytes; ++i) {
+ if ((ch & mask) == mask) {
+ *num = mask_first_byte ? ch & ~mask : ch;
+ extra_bytes = i;
+ break;
+ }
+ mask >>= 1;
+ }
+
+ if ((extra_bytes == -1) || ((1 + extra_bytes) > size))
+ return -1;
+
+ int bytes_used = 1;
+
+ for (int i = 0; i < extra_bytes; ++i)
+ *num = (*num << 8) | (0xff & buf[bytes_used++]);
+
+ return bytes_used;
+}
+
+int webm_parse_element_header(const uint8* buf, int size,
+ int* id, int64* element_size) {
scherkus (not reviewing) 2011/06/22 17:31:09 docs
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ DCHECK(buf);
+ DCHECK_GE(size, 0);
+ DCHECK(id);
+ DCHECK(element_size);
+
+ if (size == 0)
+ return 0;
+
+ int64 tmp;
+ int num_id_bytes = webm_parse_num(buf, size, 4, false, &tmp);
+
+ if (num_id_bytes <= 0)
+ return num_id_bytes;
+
+ *id = (int)tmp;
scherkus (not reviewing) 2011/06/22 17:31:09 static_cast
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+
+ int num_sz_bytes = webm_parse_num(buf + num_id_bytes,
scherkus (not reviewing) 2011/06/22 17:31:09 sz? I'm guessing it's size but I see a lot of oth
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ size - num_id_bytes,
+ 8, true, &tmp);
+
+ if (num_sz_bytes <= 0)
+ return num_sz_bytes;
+
+ *element_size = tmp;
+ return num_id_bytes + num_sz_bytes;
+}
+
+enum ElementType {
+ LIST,
+ UINT,
+ FLOAT,
+ BINARY,
+ STRING,
+ SBLOCK,
+ SKIP,
+};
+
+struct ElementIdInfo {
+ int level_;
+ ElementType type_;
+ int id_;
+};
+
+static const ElementIdInfo kClusterIds[] = {
+ {2, UINT, kWebMIdTimecode},
+ {2, SBLOCK, kWebMIdSimpleBlock},
+ {2, LIST, kWebMIdBlockGroup},
+};
+
+static const ElementIdInfo kInfoIds[] = {
+ {2, SKIP, kWebMIdSegmentUID},
+ {2, UINT, kWebMIdTimecodeScale},
+ {2, FLOAT, kWebMIdDuration},
+ {2, SKIP, kWebMIdDateUTC},
+ {2, SKIP, kWebMIdTitle},
+ {2, SKIP, kWebMIdMuxingApp},
+ {2, SKIP, kWebMIdWritingApp},
+};
+
+static const ElementIdInfo kTracksIds[] = {
+ {2, LIST, kWebMIdTrackEntry},
+};
+
+static const ElementIdInfo kTrackEntryIds[] = {
+ {3, UINT, kWebMIdTrackNumber},
+ {3, SKIP, kWebMIdTrackUID},
+ {3, UINT, kWebMIdTrackType},
+ {3, SKIP, kWebMIdFlagEnabled},
+ {3, SKIP, kWebMIdFlagDefault},
+ {3, SKIP, kWebMIdFlagForced},
+ {3, UINT, kWebMIdFlagLacing},
+ {3, UINT, kWebMIdDefaultDuration},
+ {3, SKIP, kWebMIdName},
+ {3, SKIP, kWebMIdLanguage},
+ {3, STRING, kWebMIdCodecID},
+ {3, BINARY, kWebMIdCodecPrivate},
+ {3, SKIP, kWebMIdCodecName},
+ {3, LIST, kWebMIdVideo},
+ {3, LIST, kWebMIdAudio},
+};
+
+static const ElementIdInfo kVideoIds[] = {
+ {4, SKIP, kWebMIdFlagInterlaced},
+ {4, SKIP, kWebMIdStereoMode},
+ {4, UINT, kWebMIdPixelWidth},
+ {4, UINT, kWebMIdPixelHeight},
+ {4, SKIP, kWebMIdPixelCropBottom},
+ {4, SKIP, kWebMIdPixelCropTop},
+ {4, SKIP, kWebMIdPixelCropLeft},
+ {4, SKIP, kWebMIdPixelCropRight},
+ {4, SKIP, kWebMIdDisplayWidth},
+ {4, SKIP, kWebMIdDisplayHeight},
+ {4, SKIP, kWebMIdDisplayUnit},
+ {4, SKIP, kWebMIdAspectRatioType},
+};
+
+static const ElementIdInfo kAudioIds[] = {
+ {4, SKIP, kWebMIdSamplingFrequency},
+ {4, SKIP, kWebMIdOutputSamplingFrequency},
+ {4, UINT, kWebMIdChannels},
+ {4, SKIP, kWebMIdBitDepth},
+};
+
+static const ElementIdInfo kInfoAndTracksOnly[] = {
+ {1, LIST, kWebMIdInfo},
+ {1, LIST, kWebMIdTracks},
+};
+
+static const ElementIdInfo kClustersOnly[] = {
+ {1, LIST, kWebMIdCluster},
+};
+
scherkus (not reviewing) 2011/06/22 17:31:09 nit: remove extra blank lines
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+
+
+struct ListElementInfo {
+ int id_;
+ const ElementIdInfo* id_info_;
+ int id_info_size_;
+};
+
+const ListElementInfo kListElementInfo[] = {
+ { kWebMIdCluster, kClusterIds, sizeof(kClusterIds) },
+ { kWebMIdInfo, kInfoIds, sizeof(kInfoIds) },
+ { kWebMIdTracks, kTracksIds, sizeof(kTracksIds) },
+ { kWebMIdTrackEntry, kTrackEntryIds, sizeof(kTrackEntryIds) },
+ { kWebMIdVideo, kVideoIds, sizeof(kVideoIds) },
+ { kWebMIdAudio, kAudioIds, sizeof(kAudioIds) },
+};
+
+const ElementIdInfo* webm_find_id_info(int id,
+ const ElementIdInfo* id_info,
+ int id_info_size) {
+ int count = id_info_size / sizeof(ElementIdInfo);
scherkus (not reviewing) 2011/06/22 17:31:09 nit: sizeof(*id_info)
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ for (int i = 0; i < count; ++i) {
+ if (id == id_info[i].id_)
+ return &id_info[i];
+ }
+
+ return NULL;
+}
+
+const ListElementInfo* webm_find_list_info(int id) {
+ int count = sizeof(kListElementInfo) / sizeof(ListElementInfo);
scherkus (not reviewing) 2011/06/22 17:31:09 isn't this a contsant?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ for (int i = 0; i < count; ++i) {
+ if (id == kListElementInfo[i].id_)
+ return &kListElementInfo[i];
+ }
+
+ return NULL;
+}
+
+int webm_parse_simple_block(WebMParserClient* client,
+ const uint8* buf, int size) {
+ if (size < 4)
+ return -1;
+
+ // Return an error if the trackNum > 127. We just aren't
+ // going to support large track numbers right now.
+ if ((buf[0] & 0x80) != 0x80) {
+ VLOG(1) << "TrackNumber over 127 not supported";
+ return -1;
+ }
+
+ int track_num = buf[0] & 0x7f;
+ int timecode = buf[1] << 8 | buf[2];
+ int flags = buf[3] & 0xff;
+ int lacing = (flags >> 1) & 0x3;
+
+ if (lacing != 0) {
+ VLOG(1) << "Lacing " << lacing << " not supported yet.";
+ return -1;
+ }
+
+ const uint8* frame_data = buf + 4;
+ int frame_size = size - (frame_data - buf);
+ if (!client->OnSimpleBlock(track_num, timecode, flags,
+ frame_data, frame_size)) {
+ return -1;
+ }
+
+ return size;
+}
+
+int webm_parse_elements(WebMParserClient* client,
+ const ElementIdInfo* id_info,
+ int id_info_size,
+ const uint8* buf, int size, int level) {
+ DCHECK_GE(id_info_size, 0);
+ DCHECK_GE(size, 0);
+ DCHECK_GE(level, 0);
+
+ const uint8* pCur = buf;
scherkus (not reviewing) 2011/06/22 17:31:09 pCur -> cur ?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done. Old habits sneak back in sometimes. :)
+ int cur_size = size;
+ int used = 0;
+
+ if (level > kMaxLevelDepth)
+ return -1;
+
+ while (cur_size > 0) {
+ int id;
+ int64 element_size;
+ int res = webm_parse_element_header(pCur, cur_size,
+ &id, &element_size);
+
+ if (res < 0)
+ return res;
+
+ if (res == 0)
+ break;
+
+ pCur += res;
+ cur_size -= res;
+ used += res;
+
+ // Check to see if the element is larger than the remaining data.
+ if (element_size > cur_size)
+ return -1;
+
+ const ElementIdInfo* info = webm_find_id_info(id, id_info, id_info_size);
+
+ if (info == NULL) {
+ VLOG(1) << "No info for ID " << std::hex << id;
+
+ // TODO(acolwell): Change this to return -1 after the API has solidified.
+ // We don't want to allow elements we don't recognize.
+ pCur += element_size;
+ cur_size -= element_size;
+ used += element_size;
+ continue;
+ }
+
+ if (info->level_ != level) {
+ VLOG(1) << "ID " << std::hex << id << std::dec << " at level "
+ << level << " instead of " << info->level_;
+ return -1;
+ }
+
+ if (info->type_ == SBLOCK) {
scherkus (not reviewing) 2011/06/22 17:31:09 use switch/case + helper functions to parse each t
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ int r2 = webm_parse_simple_block(client, pCur, element_size);
+ if (r2 <= 0)
+ return -1;
+
+ DCHECK_EQ(r2, element_size);
+ } else if (info->type_ == LIST) {
+ const ListElementInfo* list_info = webm_find_list_info(id);
+
+ if (!list_info) {
+ VLOG(1) << "Failed to find list info for ID " << std::hex << id;
+ return -1;
+ }
+
+ if (!client->OnListStart(id))
+ return -1;
+
+ int r2 = webm_parse_elements(client,
+ list_info->id_info_,
+ list_info->id_info_size_,
+ pCur, element_size,
+ level + 1);
+
+ if (r2 < 0)
+ return -1;
+
+ if (!client->OnListEnd(id))
+ return -1;
+
+ DCHECK_EQ(r2, element_size);
+ } else if (info->type_ == UINT) {
+ if ((element_size <= 0) || (element_size > 8))
+ return -1;
+
+ int64 tmp = 0;
+ for (int i = 0; i < element_size; ++i)
scherkus (not reviewing) 2011/06/22 17:31:09 endianess?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Added a comment indicating the integer is stored a
+ tmp = (tmp << 8) | pCur[i];
+
+ if (!client->OnUInt(id, tmp))
+ return -1;
+ } else if (info->type_ == FLOAT) {
+
scherkus (not reviewing) 2011/06/22 17:31:09 nit: remove blank line
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ if ((element_size != 4) && (element_size != 8))
+ return -1;
+
+ double value = -1;
+
+ int64 tmp = 0;
+ for (int i = 0; i < element_size; ++i)
+ tmp = (tmp << 8) | pCur[i];
+
+ if (element_size == 4) {
+ union {
+ int32 src;
+ float dst;
+ } tmp2;
+ tmp2.src = (int32)tmp;
scherkus (not reviewing) 2011/06/22 17:31:09 does ebml specify anything w.r.t. endianess?
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Yes all fields are big endian. I've added a commen
+ value = tmp2.dst;
+ } else if (element_size == 8) {
+ union {
+ int64 src;
+ double dst;
+ } tmp2;
scherkus (not reviewing) 2011/06/22 17:31:09 ditto
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 Done.
+ tmp2.src = tmp;
+ value = tmp2.dst;
+ } else {
+ return -1;
+ }
+
+ if (!client->OnFloat(id, value))
+ return -1;
+ } else if (info->type_ == BINARY) {
+ if (!client->OnBinary(id, pCur, element_size))
+ return -1;
+ } else if (info->type_ == STRING) {
+ std::string s((const char*)pCur, element_size);
scherkus (not reviewing) 2011/06/22 17:31:09 reinterpret_cast<> is the string null terminated
acolwell GONE FROM CHROMIUM 2011/06/23 16:51:28 The string is not null terminated. The constructor
+ if (!client->OnString(id, s))
+ return -1;
+ } else if (info->type_ != SKIP) {
+ VLOG(1) << "Unhandled id type " << info->type_;
+ return -1;
+ }
+
+ pCur += element_size;
+ cur_size -= element_size;
+ used += element_size;
+ }
+
+ return used;
+}
+
+int webm_parse_headers(WebMParserClient* client,
+ const uint8* buf, int size) {
+ return webm_parse_elements(client,
+ kInfoAndTracksOnly,
+ sizeof(kInfoAndTracksOnly),
+ buf, size, 1);
+}
+
+int webm_parse_cluster(WebMParserClient* client,
+ const uint8* buf, int size) {
+ return webm_parse_elements(client,
+ kClustersOnly,
+ sizeof(kClustersOnly),
+ buf, size, 1);
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698