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.
5 #include "media/cast/logging/log_deserializer.h"
9 #include "base/big_endian.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "third_party/zlib/zlib.h"
13 using media::cast::FrameEventMap
;
14 using media::cast::PacketEventMap
;
15 using media::cast::RtpTimestamp
;
16 using media::cast::proto::AggregatedFrameEvent
;
17 using media::cast::proto::AggregatedPacketEvent
;
18 using media::cast::proto::BasePacketEvent
;
19 using media::cast::proto::LogMetadata
;
23 // Use 60MB of temp buffer to hold uncompressed data if |compress| is true.
24 // This is double the size of temp buffer used during compression (30MB)
25 // since the there are two streams in the blob.
26 // Keep in sync with media/cast/logging/log_serializer.cc.
27 const int kMaxUncompressedBytes
= 60 * 1000 * 1000;
29 void MergePacketEvent(const AggregatedPacketEvent
& from
,
30 linked_ptr
<AggregatedPacketEvent
> to
) {
31 for (int i
= 0; i
< from
.base_packet_event_size(); i
++) {
32 const BasePacketEvent
& from_base_event
= from
.base_packet_event(i
);
34 for (int j
= 0; j
< to
->base_packet_event_size(); j
++) {
35 BasePacketEvent
* to_base_event
= to
->mutable_base_packet_event(j
);
36 if (from_base_event
.packet_id() == to_base_event
->packet_id()) {
37 int packet_size
= std::max(
38 from_base_event
.size(), to_base_event
->size());
39 // Need special merge logic here because we need to prevent a valid
40 // packet size (> 0) from being overwritten with an invalid one (= 0).
41 to_base_event
->MergeFrom(from_base_event
);
42 to_base_event
->set_size(packet_size
);
48 BasePacketEvent
* to_base_event
= to
->add_base_packet_event();
49 to_base_event
->CopyFrom(from_base_event
);
54 void MergeFrameEvent(const AggregatedFrameEvent
& from
,
55 linked_ptr
<AggregatedFrameEvent
> to
) {
56 to
->mutable_event_type()->MergeFrom(from
.event_type());
57 to
->mutable_event_timestamp_ms()->MergeFrom(from
.event_timestamp_ms());
58 if (!to
->has_encoded_frame_size() && from
.has_encoded_frame_size())
59 to
->set_encoded_frame_size(from
.encoded_frame_size());
60 if (!to
->has_delay_millis() && from
.has_delay_millis())
61 to
->set_delay_millis(from
.delay_millis());
62 if (!to
->has_key_frame() && from
.has_key_frame())
63 to
->set_key_frame(from
.key_frame());
64 if (!to
->has_target_bitrate() && from
.has_target_bitrate())
65 to
->set_target_bitrate(from
.target_bitrate());
68 bool PopulateDeserializedLog(base::BigEndianReader
* reader
,
69 media::cast::DeserializedLog
* log
) {
70 FrameEventMap frame_event_map
;
71 PacketEventMap packet_event_map
;
73 int num_frame_events
= log
->metadata
.num_frame_events();
74 RtpTimestamp relative_rtp_timestamp
= 0;
75 uint16 proto_size
= 0;
76 for (int i
= 0; i
< num_frame_events
; i
++) {
77 if (!reader
->ReadU16(&proto_size
))
80 linked_ptr
<AggregatedFrameEvent
> frame_event(new AggregatedFrameEvent
);
81 if (!frame_event
->ParseFromArray(reader
->ptr(), proto_size
))
83 if (!reader
->Skip(proto_size
))
86 // During serialization the RTP timestamp in proto is relative to previous
88 // Adjust RTP timestamp back to value relative to first RTP timestamp.
89 frame_event
->set_relative_rtp_timestamp(
90 frame_event
->relative_rtp_timestamp() + relative_rtp_timestamp
);
91 relative_rtp_timestamp
= frame_event
->relative_rtp_timestamp();
93 FrameEventMap::iterator it
= frame_event_map
.find(
94 frame_event
->relative_rtp_timestamp());
95 if (it
== frame_event_map
.end()) {
96 frame_event_map
.insert(
97 std::make_pair(frame_event
->relative_rtp_timestamp(), frame_event
));
99 // Events for the same frame might have been split into more than one
100 // proto. Merge them.
101 MergeFrameEvent(*frame_event
, it
->second
);
105 log
->frame_events
.swap(frame_event_map
);
107 int num_packet_events
= log
->metadata
.num_packet_events();
108 relative_rtp_timestamp
= 0;
109 for (int i
= 0; i
< num_packet_events
; i
++) {
110 if (!reader
->ReadU16(&proto_size
))
113 linked_ptr
<AggregatedPacketEvent
> packet_event(new AggregatedPacketEvent
);
114 if (!packet_event
->ParseFromArray(reader
->ptr(), proto_size
))
116 if (!reader
->Skip(proto_size
))
119 packet_event
->set_relative_rtp_timestamp(
120 packet_event
->relative_rtp_timestamp() + relative_rtp_timestamp
);
121 relative_rtp_timestamp
= packet_event
->relative_rtp_timestamp();
123 PacketEventMap::iterator it
= packet_event_map
.find(
124 packet_event
->relative_rtp_timestamp());
125 if (it
== packet_event_map
.end()) {
126 packet_event_map
.insert(
127 std::make_pair(packet_event
->relative_rtp_timestamp(), packet_event
));
129 // Events for the same frame might have been split into more than one
130 // proto. Merge them.
131 MergePacketEvent(*packet_event
, it
->second
);
135 log
->packet_events
.swap(packet_event_map
);
140 bool DoDeserializeEvents(const char* data
,
142 media::cast::DeserializedLog
* audio_log
,
143 media::cast::DeserializedLog
* video_log
) {
144 bool got_audio
= false;
145 bool got_video
= false;
146 base::BigEndianReader
reader(data
, data_bytes
);
148 LogMetadata metadata
;
149 uint16 proto_size
= 0;
150 while (reader
.remaining() > 0) {
151 if (!reader
.ReadU16(&proto_size
))
153 if (!metadata
.ParseFromArray(reader
.ptr(), proto_size
))
155 reader
.Skip(proto_size
);
157 if (metadata
.is_audio()) {
159 VLOG(1) << "Got audio data twice.";
164 audio_log
->metadata
= metadata
;
165 if (!PopulateDeserializedLog(&reader
, audio_log
))
169 VLOG(1) << "Got duplicate video log.";
174 video_log
->metadata
= metadata
;
175 if (!PopulateDeserializedLog(&reader
, video_log
))
182 bool Uncompress(const char* data
,
184 int max_uncompressed_bytes
,
186 int* uncompressed_bytes
) {
187 z_stream stream
= {0};
189 stream
.next_in
= reinterpret_cast<uint8
*>(const_cast<char*>(data
));
190 stream
.avail_in
= data_bytes
;
191 stream
.next_out
= reinterpret_cast<uint8
*>(uncompressed
);
192 stream
.avail_out
= max_uncompressed_bytes
;
194 bool success
= false;
195 while (stream
.avail_in
> 0 && stream
.avail_out
> 0) {
196 // 16 is added to read in gzip format.
197 int result
= inflateInit2(&stream
, MAX_WBITS
+ 16);
198 DCHECK_EQ(Z_OK
, result
);
200 result
= inflate(&stream
, Z_FINISH
);
201 success
= (result
== Z_STREAM_END
);
203 DVLOG(2) << "inflate() failed. Result: " << result
;
207 result
= inflateEnd(&stream
);
208 DCHECK(result
== Z_OK
);
211 if (stream
.avail_in
== 0) {
213 *uncompressed_bytes
= max_uncompressed_bytes
- stream
.avail_out
;
223 bool DeserializeEvents(const char* data
,
226 DeserializedLog
* audio_log
,
227 DeserializedLog
* video_log
) {
228 DCHECK_GT(data_bytes
, 0);
231 scoped_ptr
<char[]> uncompressed(new char[kMaxUncompressedBytes
]);
232 int uncompressed_bytes
= 0;
233 if (!Uncompress(data
,
235 kMaxUncompressedBytes
,
237 &uncompressed_bytes
))
240 return DoDeserializeEvents(
241 uncompressed
.get(), uncompressed_bytes
, audio_log
, video_log
);
243 return DoDeserializeEvents(data
, data_bytes
, audio_log
, video_log
);
247 DeserializedLog::DeserializedLog() {}
248 DeserializedLog::~DeserializedLog() {}