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