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 to_base_event
->MergeFrom(from_base_event
);
44 BasePacketEvent
* to_base_event
= to
->add_base_packet_event();
45 to_base_event
->CopyFrom(from_base_event
);
50 void MergeFrameEvent(const AggregatedFrameEvent
& from
,
51 linked_ptr
<AggregatedFrameEvent
> to
) {
52 to
->mutable_event_type()->MergeFrom(from
.event_type());
53 to
->mutable_event_timestamp_ms()->MergeFrom(from
.event_timestamp_ms());
54 if (!to
->has_encoded_frame_size() && from
.has_encoded_frame_size())
55 to
->set_encoded_frame_size(from
.encoded_frame_size());
56 if (!to
->has_delay_millis() && from
.has_delay_millis())
57 to
->set_delay_millis(from
.delay_millis());
58 if (!to
->has_key_frame() && from
.has_key_frame())
59 to
->set_key_frame(from
.key_frame());
60 if (!to
->has_target_bitrate() && from
.has_target_bitrate())
61 to
->set_target_bitrate(from
.target_bitrate());
64 bool PopulateDeserializedLog(base::BigEndianReader
* reader
,
65 media::cast::DeserializedLog
* log
) {
66 FrameEventMap frame_event_map
;
67 PacketEventMap packet_event_map
;
69 int num_frame_events
= log
->metadata
.num_frame_events();
70 RtpTimestamp relative_rtp_timestamp
= 0;
71 uint16 proto_size
= 0;
72 for (int i
= 0; i
< num_frame_events
; i
++) {
73 if (!reader
->ReadU16(&proto_size
))
76 linked_ptr
<AggregatedFrameEvent
> frame_event(new AggregatedFrameEvent
);
77 if (!frame_event
->ParseFromArray(reader
->ptr(), proto_size
))
79 if (!reader
->Skip(proto_size
))
82 // During serialization the RTP timestamp in proto is relative to previous
84 // Adjust RTP timestamp back to value relative to first RTP timestamp.
85 frame_event
->set_relative_rtp_timestamp(
86 frame_event
->relative_rtp_timestamp() + relative_rtp_timestamp
);
87 relative_rtp_timestamp
= frame_event
->relative_rtp_timestamp();
89 FrameEventMap::iterator it
= frame_event_map
.find(
90 frame_event
->relative_rtp_timestamp());
91 if (it
== frame_event_map
.end()) {
92 frame_event_map
.insert(
93 std::make_pair(frame_event
->relative_rtp_timestamp(), frame_event
));
95 // Events for the same frame might have been split into more than one
97 MergeFrameEvent(*frame_event
, it
->second
);
101 log
->frame_events
.swap(frame_event_map
);
103 int num_packet_events
= log
->metadata
.num_packet_events();
104 relative_rtp_timestamp
= 0;
105 for (int i
= 0; i
< num_packet_events
; i
++) {
106 if (!reader
->ReadU16(&proto_size
))
109 linked_ptr
<AggregatedPacketEvent
> packet_event(new AggregatedPacketEvent
);
110 if (!packet_event
->ParseFromArray(reader
->ptr(), proto_size
))
112 if (!reader
->Skip(proto_size
))
115 packet_event
->set_relative_rtp_timestamp(
116 packet_event
->relative_rtp_timestamp() + relative_rtp_timestamp
);
117 relative_rtp_timestamp
= packet_event
->relative_rtp_timestamp();
119 PacketEventMap::iterator it
= packet_event_map
.find(
120 packet_event
->relative_rtp_timestamp());
121 if (it
== packet_event_map
.end()) {
122 packet_event_map
.insert(
123 std::make_pair(packet_event
->relative_rtp_timestamp(), packet_event
));
125 // Events for the same frame might have been split into more than one
126 // proto. Merge them.
127 MergePacketEvent(*packet_event
, it
->second
);
131 log
->packet_events
.swap(packet_event_map
);
136 bool DoDeserializeEvents(const char* data
,
138 media::cast::DeserializedLog
* audio_log
,
139 media::cast::DeserializedLog
* video_log
) {
140 bool got_audio
= false;
141 bool got_video
= false;
142 base::BigEndianReader
reader(data
, data_bytes
);
144 LogMetadata metadata
;
145 uint16 proto_size
= 0;
146 while (reader
.remaining() > 0) {
147 if (!reader
.ReadU16(&proto_size
))
149 if (!metadata
.ParseFromArray(reader
.ptr(), proto_size
))
151 reader
.Skip(proto_size
);
153 if (metadata
.is_audio()) {
155 VLOG(1) << "Got audio data twice.";
160 audio_log
->metadata
= metadata
;
161 if (!PopulateDeserializedLog(&reader
, audio_log
))
165 VLOG(1) << "Got duplicate video log.";
170 video_log
->metadata
= metadata
;
171 if (!PopulateDeserializedLog(&reader
, video_log
))
178 bool Uncompress(const char* data
,
180 int max_uncompressed_bytes
,
182 int* uncompressed_bytes
) {
183 z_stream stream
= {0};
185 stream
.next_in
= reinterpret_cast<uint8
*>(const_cast<char*>(data
));
186 stream
.avail_in
= data_bytes
;
187 stream
.next_out
= reinterpret_cast<uint8
*>(uncompressed
);
188 stream
.avail_out
= max_uncompressed_bytes
;
190 bool success
= false;
191 while (stream
.avail_in
> 0 && stream
.avail_out
> 0) {
192 // 16 is added to read in gzip format.
193 int result
= inflateInit2(&stream
, MAX_WBITS
+ 16);
194 DCHECK_EQ(Z_OK
, result
);
196 result
= inflate(&stream
, Z_FINISH
);
197 success
= (result
== Z_STREAM_END
);
199 DVLOG(2) << "inflate() failed. Result: " << result
;
203 result
= inflateEnd(&stream
);
204 DCHECK(result
== Z_OK
);
207 if (stream
.avail_in
== 0) {
209 *uncompressed_bytes
= max_uncompressed_bytes
- stream
.avail_out
;
219 bool DeserializeEvents(const char* data
,
222 DeserializedLog
* audio_log
,
223 DeserializedLog
* video_log
) {
224 DCHECK_GT(data_bytes
, 0);
227 scoped_ptr
<char[]> uncompressed(new char[kMaxUncompressedBytes
]);
228 int uncompressed_bytes
= 0;
229 if (!Uncompress(data
,
231 kMaxUncompressedBytes
,
233 &uncompressed_bytes
))
236 return DoDeserializeEvents(
237 uncompressed
.get(), uncompressed_bytes
, audio_log
, video_log
);
239 return DoDeserializeEvents(data
, data_bytes
, audio_log
, video_log
);
243 DeserializedLog::DeserializedLog() {}
244 DeserializedLog::~DeserializedLog() {}