Home | History | Annotate | Download | only in logging
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/cast/logging/log_deserializer.h"
      6 
      7 #include <map>
      8 #include <utility>
      9 
     10 #include "base/big_endian.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "third_party/zlib/zlib.h"
     13 
     14 using media::cast::FrameEventMap;
     15 using media::cast::PacketEventMap;
     16 using media::cast::RtpTimestamp;
     17 using media::cast::proto::AggregatedFrameEvent;
     18 using media::cast::proto::AggregatedPacketEvent;
     19 using media::cast::proto::BasePacketEvent;
     20 using media::cast::proto::LogMetadata;
     21 
     22 namespace {
     23 
     24 // Use 60MB of temp buffer to hold uncompressed data if |compress| is true.
     25 // This is double the size of temp buffer used during compression (30MB)
     26 // since the there are two streams in the blob.
     27 // Keep in sync with media/cast/logging/log_serializer.cc.
     28 const int kMaxUncompressedBytes = 60 * 1000 * 1000;
     29 
     30 void MergePacketEvent(const AggregatedPacketEvent& from,
     31     linked_ptr<AggregatedPacketEvent> to) {
     32   for (int i = 0; i < from.base_packet_event_size(); i++) {
     33     const BasePacketEvent& from_base_event = from.base_packet_event(i);
     34     bool merged = false;
     35     for (int j = 0; j < to->base_packet_event_size(); j++) {
     36       BasePacketEvent* to_base_event = to->mutable_base_packet_event(j);
     37       if (from_base_event.packet_id() == to_base_event->packet_id()) {
     38         int packet_size = std::max(
     39             from_base_event.size(), to_base_event->size());
     40         // Need special merge logic here because we need to prevent a valid
     41         // packet size (> 0) from being overwritten with an invalid one (= 0).
     42         to_base_event->MergeFrom(from_base_event);
     43         to_base_event->set_size(packet_size);
     44         merged = true;
     45         break;
     46       }
     47     }
     48     if (!merged) {
     49       BasePacketEvent* to_base_event = to->add_base_packet_event();
     50       to_base_event->CopyFrom(from_base_event);
     51     }
     52   }
     53 }
     54 
     55 void MergeFrameEvent(const AggregatedFrameEvent& from,
     56     linked_ptr<AggregatedFrameEvent> to) {
     57   to->mutable_event_type()->MergeFrom(from.event_type());
     58   to->mutable_event_timestamp_ms()->MergeFrom(from.event_timestamp_ms());
     59   if (!to->has_encoded_frame_size() && from.has_encoded_frame_size())
     60     to->set_encoded_frame_size(from.encoded_frame_size());
     61   if (!to->has_delay_millis() && from.has_delay_millis())
     62     to->set_delay_millis(from.delay_millis());
     63   if (!to->has_key_frame() && from.has_key_frame())
     64     to->set_key_frame(from.key_frame());
     65   if (!to->has_target_bitrate() && from.has_target_bitrate())
     66     to->set_target_bitrate(from.target_bitrate());
     67 }
     68 
     69 bool PopulateDeserializedLog(base::BigEndianReader* reader,
     70                              media::cast::DeserializedLog* log) {
     71   FrameEventMap frame_event_map;
     72   PacketEventMap packet_event_map;
     73 
     74   int num_frame_events = log->metadata.num_frame_events();
     75   RtpTimestamp relative_rtp_timestamp = 0;
     76   uint16 proto_size = 0;
     77   for (int i = 0; i < num_frame_events; i++) {
     78     if (!reader->ReadU16(&proto_size))
     79       return false;
     80 
     81     linked_ptr<AggregatedFrameEvent> frame_event(new AggregatedFrameEvent);
     82     if (!frame_event->ParseFromArray(reader->ptr(), proto_size))
     83       return false;
     84     if (!reader->Skip(proto_size))
     85       return false;
     86 
     87     // During serialization the RTP timestamp in proto is relative to previous
     88     // frame.
     89     // Adjust RTP timestamp back to value relative to first RTP timestamp.
     90     frame_event->set_relative_rtp_timestamp(
     91         frame_event->relative_rtp_timestamp() + relative_rtp_timestamp);
     92     relative_rtp_timestamp = frame_event->relative_rtp_timestamp();
     93 
     94     FrameEventMap::iterator it = frame_event_map.find(
     95         frame_event->relative_rtp_timestamp());
     96     if (it == frame_event_map.end()) {
     97       frame_event_map.insert(
     98           std::make_pair(frame_event->relative_rtp_timestamp(), frame_event));
     99     } else {
    100       // Events for the same frame might have been split into more than one
    101       // proto. Merge them.
    102       MergeFrameEvent(*frame_event, it->second);
    103     }
    104   }
    105 
    106   log->frame_events.swap(frame_event_map);
    107 
    108   int num_packet_events = log->metadata.num_packet_events();
    109   relative_rtp_timestamp = 0;
    110   for (int i = 0; i < num_packet_events; i++) {
    111     if (!reader->ReadU16(&proto_size))
    112       return false;
    113 
    114     linked_ptr<AggregatedPacketEvent> packet_event(new AggregatedPacketEvent);
    115     if (!packet_event->ParseFromArray(reader->ptr(), proto_size))
    116       return false;
    117     if (!reader->Skip(proto_size))
    118       return false;
    119 
    120     packet_event->set_relative_rtp_timestamp(
    121         packet_event->relative_rtp_timestamp() + relative_rtp_timestamp);
    122     relative_rtp_timestamp = packet_event->relative_rtp_timestamp();
    123 
    124     PacketEventMap::iterator it = packet_event_map.find(
    125         packet_event->relative_rtp_timestamp());
    126     if (it == packet_event_map.end()) {
    127       packet_event_map.insert(
    128           std::make_pair(packet_event->relative_rtp_timestamp(), packet_event));
    129     } else {
    130       // Events for the same frame might have been split into more than one
    131       // proto. Merge them.
    132       MergePacketEvent(*packet_event, it->second);
    133     }
    134   }
    135 
    136   log->packet_events.swap(packet_event_map);
    137 
    138   return true;
    139 }
    140 
    141 bool DoDeserializeEvents(const char* data,
    142                          int data_bytes,
    143                          media::cast::DeserializedLog* audio_log,
    144                          media::cast::DeserializedLog* video_log) {
    145   bool got_audio = false;
    146   bool got_video = false;
    147   base::BigEndianReader reader(data, data_bytes);
    148 
    149   LogMetadata metadata;
    150   uint16 proto_size = 0;
    151   while (reader.remaining() > 0) {
    152     if (!reader.ReadU16(&proto_size))
    153       return false;
    154     if (!metadata.ParseFromArray(reader.ptr(), proto_size))
    155       return false;
    156     reader.Skip(proto_size);
    157 
    158     if (metadata.is_audio()) {
    159       if (got_audio) {
    160         VLOG(1) << "Got audio data twice.";
    161         return false;
    162       }
    163 
    164       got_audio = true;
    165       audio_log->metadata = metadata;
    166       if (!PopulateDeserializedLog(&reader, audio_log))
    167         return false;
    168     } else {
    169       if (got_video) {
    170         VLOG(1) << "Got duplicate video log.";
    171         return false;
    172       }
    173 
    174       got_video = true;
    175       video_log->metadata = metadata;
    176       if (!PopulateDeserializedLog(&reader, video_log))
    177         return false;
    178     }
    179   }
    180   return true;
    181 }
    182 
    183 bool Uncompress(const char* data,
    184                 int data_bytes,
    185                 int max_uncompressed_bytes,
    186                 char* uncompressed,
    187                 int* uncompressed_bytes) {
    188   z_stream stream = {0};
    189 
    190   stream.next_in = reinterpret_cast<uint8*>(const_cast<char*>(data));
    191   stream.avail_in = data_bytes;
    192   stream.next_out = reinterpret_cast<uint8*>(uncompressed);
    193   stream.avail_out = max_uncompressed_bytes;
    194 
    195   bool success = false;
    196   while (stream.avail_in > 0 && stream.avail_out > 0) {
    197     // 16 is added to read in gzip format.
    198     int result = inflateInit2(&stream, MAX_WBITS + 16);
    199     DCHECK_EQ(Z_OK, result);
    200 
    201     result = inflate(&stream, Z_FINISH);
    202     success = (result == Z_STREAM_END);
    203     if (!success) {
    204       DVLOG(2) << "inflate() failed. Result: " << result;
    205       break;
    206     }
    207 
    208     result = inflateEnd(&stream);
    209     DCHECK(result == Z_OK);
    210   }
    211 
    212   if (stream.avail_in == 0) {
    213     success = true;
    214     *uncompressed_bytes = max_uncompressed_bytes - stream.avail_out;
    215   }
    216   return success;
    217 }
    218 
    219 }  // namespace
    220 
    221 namespace media {
    222 namespace cast {
    223 
    224 bool DeserializeEvents(const char* data,
    225                        int data_bytes,
    226                        bool compressed,
    227                        DeserializedLog* audio_log,
    228                        DeserializedLog* video_log) {
    229   DCHECK_GT(data_bytes, 0);
    230 
    231   if (compressed) {
    232     scoped_ptr<char[]> uncompressed(new char[kMaxUncompressedBytes]);
    233     int uncompressed_bytes = 0;
    234     if (!Uncompress(data,
    235                     data_bytes,
    236                     kMaxUncompressedBytes,
    237                     uncompressed.get(),
    238                     &uncompressed_bytes))
    239       return false;
    240 
    241     return DoDeserializeEvents(
    242         uncompressed.get(), uncompressed_bytes, audio_log, video_log);
    243   } else {
    244     return DoDeserializeEvents(data, data_bytes, audio_log, video_log);
    245   }
    246 }
    247 
    248 DeserializedLog::DeserializedLog() {}
    249 DeserializedLog::~DeserializedLog() {}
    250 
    251 }  // namespace cast
    252 }  // namespace media
    253