Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / cast / logging / log_deserializer.cc
index dc1d78d..5621be0 100644 (file)
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/big_endian.h"
+#include "base/memory/scoped_ptr.h"
 #include "third_party/zlib/zlib.h"
 
 using media::cast::FrameEventMap;
@@ -15,40 +16,65 @@ using media::cast::PacketEventMap;
 using media::cast::RtpTimestamp;
 using media::cast::proto::AggregatedFrameEvent;
 using media::cast::proto::AggregatedPacketEvent;
+using media::cast::proto::BasePacketEvent;
 using media::cast::proto::LogMetadata;
 
 namespace {
 
-// Use 30MB of temp buffer to hold uncompressed data if |compress| is true.
-const int kMaxUncompressedBytes = 30 * 1000 * 1000;
+// Use 60MB of temp buffer to hold uncompressed data if |compress| is true.
+// This is double the size of temp buffer used during compression (30MB)
+// since the there are two streams in the blob.
+// Keep in sync with media/cast/logging/log_serializer.cc.
+const int kMaxUncompressedBytes = 60 * 1000 * 1000;
+
+void MergePacketEvent(const AggregatedPacketEvent& from,
+    linked_ptr<AggregatedPacketEvent> to) {
+  for (int i = 0; i < from.base_packet_event_size(); i++) {
+    const BasePacketEvent& from_base_event = from.base_packet_event(i);
+    bool merged = false;
+    for (int j = 0; j < to->base_packet_event_size(); j++) {
+      BasePacketEvent* to_base_event = to->mutable_base_packet_event(i);
+      if (from_base_event.packet_id() == to_base_event->packet_id()) {
+        to_base_event->MergeFrom(from_base_event);
+        merged = true;
+        break;
+      }
+    }
+    if (!merged) {
+      BasePacketEvent* to_base_event = to->add_base_packet_event();
+      to_base_event->CopyFrom(from_base_event);
+    }
+  }
+}
 
-bool DoDeserializeEvents(char* data,
-                         int data_bytes,
-                         LogMetadata* metadata,
-                         FrameEventMap* frame_events,
-                         PacketEventMap* packet_events) {
-  base::BigEndianReader reader(data, data_bytes);
+void MergeFrameEvent(const AggregatedFrameEvent& from,
+    linked_ptr<AggregatedFrameEvent> to) {
+  to->mutable_event_type()->MergeFrom(from.event_type());
+  to->mutable_event_timestamp_ms()->MergeFrom(from.event_timestamp_ms());
+  if (!to->has_encoded_frame_size())
+    to->set_encoded_frame_size(from.encoded_frame_size());
+  if (!to->has_delay_millis())
+    to->set_delay_millis(from.delay_millis());
+  if (!to->has_key_frame())
+    to->set_key_frame(from.key_frame());
+}
 
-  uint16 proto_size;
-  if (!reader.ReadU16(&proto_size))
-    return false;
-  if (!metadata->ParseFromArray(reader.ptr(), proto_size))
-    return false;
-  if (!reader.Skip(proto_size))
-    return false;
+bool PopulateDeserializedLog(base::BigEndianReader* reader,
+                             media::cast::DeserializedLog* log) {
   FrameEventMap frame_event_map;
   PacketEventMap packet_event_map;
 
-  int num_frame_events = metadata->num_frame_events();
+  int num_frame_events = log->metadata.num_frame_events();
   RtpTimestamp relative_rtp_timestamp = 0;
+  uint16 proto_size = 0;
   for (int i = 0; i < num_frame_events; i++) {
-    if (!reader.ReadU16(&proto_size))
+    if (!reader->ReadU16(&proto_size))
       return false;
 
     linked_ptr<AggregatedFrameEvent> frame_event(new AggregatedFrameEvent);
-    if (!frame_event->ParseFromArray(reader.ptr(), proto_size))
+    if (!frame_event->ParseFromArray(reader->ptr(), proto_size))
       return false;
-    if (!reader.Skip(proto_size))
+    if (!reader->Skip(proto_size))
       return false;
 
     // During serialization the RTP timestamp in proto is relative to previous
@@ -58,95 +84,146 @@ bool DoDeserializeEvents(char* data,
         frame_event->relative_rtp_timestamp() + relative_rtp_timestamp);
     relative_rtp_timestamp = frame_event->relative_rtp_timestamp();
 
-    std::pair<FrameEventMap::iterator, bool> result = frame_event_map.insert(
-        std::make_pair(frame_event->relative_rtp_timestamp(), frame_event));
-    if (!result.second) {
-      VLOG(1) << "Duplicate frame event entry detected: "
-              << frame_event->relative_rtp_timestamp();
-      return false;
+    FrameEventMap::iterator it = frame_event_map.find(
+        frame_event->relative_rtp_timestamp());
+    if (it == frame_event_map.end()) {
+      frame_event_map.insert(
+          std::make_pair(frame_event->relative_rtp_timestamp(), frame_event));
+    } else {
+      // Events for the same frame might have been split into more than one
+      // proto. Merge them.
+      MergeFrameEvent(*frame_event, it->second);
     }
   }
 
-  frame_events->swap(frame_event_map);
+  log->frame_events.swap(frame_event_map);
 
-  int num_packet_events = metadata->num_packet_events();
+  int num_packet_events = log->metadata.num_packet_events();
   relative_rtp_timestamp = 0;
   for (int i = 0; i < num_packet_events; i++) {
-    if (!reader.ReadU16(&proto_size))
+    if (!reader->ReadU16(&proto_size))
       return false;
 
     linked_ptr<AggregatedPacketEvent> packet_event(new AggregatedPacketEvent);
-    if (!packet_event->ParseFromArray(reader.ptr(), proto_size))
+    if (!packet_event->ParseFromArray(reader->ptr(), proto_size))
       return false;
-    if (!reader.Skip(proto_size))
+    if (!reader->Skip(proto_size))
       return false;
 
     packet_event->set_relative_rtp_timestamp(
         packet_event->relative_rtp_timestamp() + relative_rtp_timestamp);
     relative_rtp_timestamp = packet_event->relative_rtp_timestamp();
 
-    std::pair<PacketEventMap::iterator, bool> result = packet_event_map.insert(
-        std::make_pair(packet_event->relative_rtp_timestamp(), packet_event));
-    if (!result.second) {
-      VLOG(1) << "Duplicate packet event entry detected: "
-              << packet_event->relative_rtp_timestamp();
-      return false;
+    PacketEventMap::iterator it = packet_event_map.find(
+        packet_event->relative_rtp_timestamp());
+    if (it == packet_event_map.end()) {
+      packet_event_map.insert(
+          std::make_pair(packet_event->relative_rtp_timestamp(), packet_event));
+    } else {
+      // Events for the same frame might have been split into more than one
+      // proto. Merge them.
+      MergePacketEvent(*packet_event, it->second);
     }
   }
 
-  packet_events->swap(packet_event_map);
+  log->packet_events.swap(packet_event_map);
+
+  return true;
+}
+
+bool DoDeserializeEvents(const char* data,
+                         int data_bytes,
+                         media::cast::DeserializedLog* audio_log,
+                         media::cast::DeserializedLog* video_log) {
+  bool got_audio = false;
+  bool got_video = false;
+  base::BigEndianReader reader(data, data_bytes);
 
+  LogMetadata metadata;
+  uint16 proto_size = 0;
+  while (reader.remaining() > 0) {
+    if (!reader.ReadU16(&proto_size))
+      return false;
+    if (!metadata.ParseFromArray(reader.ptr(), proto_size))
+      return false;
+    reader.Skip(proto_size);
+
+    if (metadata.is_audio()) {
+      if (got_audio) {
+        VLOG(1) << "Got audio data twice.";
+        return false;
+      }
+
+      got_audio = true;
+      audio_log->metadata = metadata;
+      if (!PopulateDeserializedLog(&reader, audio_log))
+        return false;
+    } else {
+      if (got_video) {
+        VLOG(1) << "Got duplicate video log.";
+        return false;
+      }
+
+      got_video = true;
+      video_log->metadata = metadata;
+      if (!PopulateDeserializedLog(&reader, video_log))
+        return false;
+    }
+  }
   return true;
 }
 
-bool Uncompress(char* data,
+bool Uncompress(const char* data,
                 int data_bytes,
                 int max_uncompressed_bytes,
                 char* uncompressed,
                 int* uncompressed_bytes) {
   z_stream stream = {0};
-  // 16 is added to read in gzip format.
-  int result = inflateInit2(&stream, MAX_WBITS + 16);
-  DCHECK_EQ(Z_OK, result);
 
-  stream.next_in = reinterpret_cast<uint8*>(data);
+  stream.next_in = reinterpret_cast<uint8*>(const_cast<char*>(data));
   stream.avail_in = data_bytes;
   stream.next_out = reinterpret_cast<uint8*>(uncompressed);
   stream.avail_out = max_uncompressed_bytes;
 
-  result = inflate(&stream, Z_FINISH);
-  bool success = (result == Z_STREAM_END);
-  if (!success)
-    DVLOG(2) << "inflate() failed. Result: " << result;
+  bool success = false;
+  while (stream.avail_in > 0 && stream.avail_out > 0) {
+    // 16 is added to read in gzip format.
+    int result = inflateInit2(&stream, MAX_WBITS + 16);
+    DCHECK_EQ(Z_OK, result);
+
+    result = inflate(&stream, Z_FINISH);
+    success = (result == Z_STREAM_END);
+    if (!success) {
+      DVLOG(2) << "inflate() failed. Result: " << result;
+      break;
+    }
 
-  result = inflateEnd(&stream);
-  DCHECK(result == Z_OK);
+    result = inflateEnd(&stream);
+    DCHECK(result == Z_OK);
+  }
 
-  if (success)
+  if (stream.avail_in == 0) {
+    success = true;
     *uncompressed_bytes = max_uncompressed_bytes - stream.avail_out;
-
+  }
   return success;
 }
+
 }  // namespace
 
 namespace media {
 namespace cast {
 
-bool DeserializeEvents(char* data,
+bool DeserializeEvents(const char* data,
                        int data_bytes,
                        bool compressed,
-                       LogMetadata* log_metadata,
-                       FrameEventMap* frame_events,
-                       PacketEventMap* packet_events) {
-  DCHECK(data);
+                       DeserializedLog* audio_log,
+                       DeserializedLog* video_log) {
   DCHECK_GT(data_bytes, 0);
-  DCHECK(log_metadata);
-  DCHECK(frame_events);
-  DCHECK(packet_events);
 
   if (compressed) {
     scoped_ptr<char[]> uncompressed(new char[kMaxUncompressedBytes]);
-    int uncompressed_bytes;
+    int uncompressed_bytes = 0;
     if (!Uncompress(data,
                     data_bytes,
                     kMaxUncompressedBytes,
@@ -154,16 +231,15 @@ bool DeserializeEvents(char* data,
                     &uncompressed_bytes))
       return false;
 
-    return DoDeserializeEvents(uncompressed.get(),
-                               uncompressed_bytes,
-                               log_metadata,
-                               frame_events,
-                               packet_events);
-  } else {
     return DoDeserializeEvents(
-        data, data_bytes, log_metadata, frame_events, packet_events);
+        uncompressed.get(), uncompressed_bytes, audio_log, video_log);
+  } else {
+    return DoDeserializeEvents(data, data_bytes, audio_log, video_log);
   }
 }
 
+DeserializedLog::DeserializedLog() {}
+DeserializedLog::~DeserializedLog() {}
+
 }  // namespace cast
 }  // namespace media