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"
10 #include "base/big_endian.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "third_party/zlib/zlib.h"
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
;
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;
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
);
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
);
49 BasePacketEvent
* to_base_event
= to
->add_base_packet_event();
50 to_base_event
->CopyFrom(from_base_event
);
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());
69 bool PopulateDeserializedLog(base::BigEndianReader
* reader
,
70 media::cast::DeserializedLog
* log
) {
71 FrameEventMap frame_event_map
;
72 PacketEventMap packet_event_map
;
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
))
81 linked_ptr
<AggregatedFrameEvent
> frame_event(new AggregatedFrameEvent
);
82 if (!frame_event
->ParseFromArray(reader
->ptr(), proto_size
))
84 if (!reader
->Skip(proto_size
))
87 // During serialization the RTP timestamp in proto is relative to previous
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();
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
));
100 // Events for the same frame might have been split into more than one
101 // proto. Merge them.
102 MergeFrameEvent(*frame_event
, it
->second
);
106 log
->frame_events
.swap(frame_event_map
);
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
))
114 linked_ptr
<AggregatedPacketEvent
> packet_event(new AggregatedPacketEvent
);
115 if (!packet_event
->ParseFromArray(reader
->ptr(), proto_size
))
117 if (!reader
->Skip(proto_size
))
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();
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
));
130 // Events for the same frame might have been split into more than one
131 // proto. Merge them.
132 MergePacketEvent(*packet_event
, it
->second
);
136 log
->packet_events
.swap(packet_event_map
);
141 bool DoDeserializeEvents(const char* data
,
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
);
149 LogMetadata metadata
;
150 uint16 proto_size
= 0;
151 while (reader
.remaining() > 0) {
152 if (!reader
.ReadU16(&proto_size
))
154 if (!metadata
.ParseFromArray(reader
.ptr(), proto_size
))
156 reader
.Skip(proto_size
);
158 if (metadata
.is_audio()) {
160 VLOG(1) << "Got audio data twice.";
165 audio_log
->metadata
= metadata
;
166 if (!PopulateDeserializedLog(&reader
, audio_log
))
170 VLOG(1) << "Got duplicate video log.";
175 video_log
->metadata
= metadata
;
176 if (!PopulateDeserializedLog(&reader
, video_log
))
183 bool Uncompress(const char* data
,
185 int max_uncompressed_bytes
,
187 int* uncompressed_bytes
) {
188 z_stream stream
= {0};
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
;
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
);
201 result
= inflate(&stream
, Z_FINISH
);
202 success
= (result
== Z_STREAM_END
);
204 DVLOG(2) << "inflate() failed. Result: " << result
;
208 result
= inflateEnd(&stream
);
209 DCHECK(result
== Z_OK
);
212 if (stream
.avail_in
== 0) {
214 *uncompressed_bytes
= max_uncompressed_bytes
- stream
.avail_out
;
224 bool DeserializeEvents(const char* data
,
227 DeserializedLog
* audio_log
,
228 DeserializedLog
* video_log
) {
229 DCHECK_GT(data_bytes
, 0);
232 scoped_ptr
<char[]> uncompressed(new char[kMaxUncompressedBytes
]);
233 int uncompressed_bytes
= 0;
234 if (!Uncompress(data
,
236 kMaxUncompressedBytes
,
238 &uncompressed_bytes
))
241 return DoDeserializeEvents(
242 uncompressed
.get(), uncompressed_bytes
, audio_log
, video_log
);
244 return DoDeserializeEvents(data
, data_bytes
, audio_log
, video_log
);
248 DeserializedLog::DeserializedLog() {}
249 DeserializedLog::~DeserializedLog() {}