1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The serialization format is as follows: 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 16-bit integer describing the following LogMetadata proto size in bytes. 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// The LogMetadata proto. 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// 32-bit integer describing number of frame events. 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// (The following repeated for number of frame events): 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// 16-bit integer describing the following AggregatedFrameEvent proto size 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// in bytes. 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The AggregatedFrameEvent proto. 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// 32-bit integer describing number of packet events. 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// (The following repeated for number of packet events): 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// 16-bit integer describing the following AggregatedPacketEvent proto 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// size in bytes. 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The AggregatedPacketEvent proto. 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/cast/logging/log_serializer.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/big_endian.h" 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h" 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/scoped_ptr.h" 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/zlib/zlib.h" 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace media { 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace cast { 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace { 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using media::cast::proto::AggregatedFrameEvent; 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using media::cast::proto::AggregatedPacketEvent; 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using media::cast::proto::LogMetadata; 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use 30MB of temp buffer to hold uncompressed data if |compress| is true. 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kMaxUncompressedBytes = 30 * 1000 * 1000; 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// The maximum allowed size per serialized proto. 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kMaxSerializedProtoBytes = (1 << 16) - 1; 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool DoSerializeEvents(const LogMetadata& metadata, 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const FrameEventList& frame_events, 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const PacketEventList& packet_events, 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const int max_output_bytes, 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) char* output, 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int* output_bytes) { 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::BigEndianWriter writer(output, max_output_bytes); 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int proto_size = metadata.ByteSize(); 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(proto_size <= kMaxSerializedProtoBytes); 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.WriteU16(proto_size)) 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!metadata.SerializeToArray(writer.ptr(), writer.remaining())) 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.Skip(proto_size)) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RtpTimestamp prev_rtp_timestamp = 0; 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (media::cast::FrameEventList::const_iterator it = frame_events.begin(); 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) it != frame_events.end(); 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++it) { 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu media::cast::proto::AggregatedFrameEvent frame_event(**it); 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Adjust relative RTP timestamp so that it is relative to previous frame, 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // rather than relative to first RTP timestamp. 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This is done to improve encoding size. 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu RtpTimestamp old_relative_rtp_timestamp = 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu frame_event.relative_rtp_timestamp(); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) frame_event.set_relative_rtp_timestamp( 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu old_relative_rtp_timestamp - prev_rtp_timestamp); 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu prev_rtp_timestamp = old_relative_rtp_timestamp; 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) proto_size = frame_event.ByteSize(); 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(proto_size <= kMaxSerializedProtoBytes); 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Write size of the proto, then write the proto. 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.WriteU16(proto_size)) 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!frame_event.SerializeToArray(writer.ptr(), writer.remaining())) 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.Skip(proto_size)) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Write packet events. 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) prev_rtp_timestamp = 0; 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (media::cast::PacketEventList::const_iterator it = packet_events.begin(); 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) it != packet_events.end(); 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++it) { 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu media::cast::proto::AggregatedPacketEvent packet_event(**it); 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu RtpTimestamp old_relative_rtp_timestamp = 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu packet_event.relative_rtp_timestamp(); 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) packet_event.set_relative_rtp_timestamp( 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu old_relative_rtp_timestamp - prev_rtp_timestamp); 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu prev_rtp_timestamp = old_relative_rtp_timestamp; 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) proto_size = packet_event.ByteSize(); 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(proto_size <= kMaxSerializedProtoBytes); 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Write size of the proto, then write the proto. 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.WriteU16(proto_size)) 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!packet_event.SerializeToArray(writer.ptr(), writer.remaining())) 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!writer.Skip(proto_size)) 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *output_bytes = max_output_bytes - writer.remaining(); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Compress(char* uncompressed_buffer, 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int uncompressed_bytes, 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int max_output_bytes, 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) char* output, 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int* output_bytes) { 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) z_stream stream = {0}; 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int result = deflateInit2(&stream, 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Z_DEFAULT_COMPRESSION, 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Z_DEFLATED, 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 16 is added to produce a gzip header + trailer. 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MAX_WBITS + 16, 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 8, // memLevel = 8 is default. 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Z_DEFAULT_STRATEGY); 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_EQ(Z_OK, result); 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) stream.next_in = reinterpret_cast<uint8*>(uncompressed_buffer); 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) stream.avail_in = uncompressed_bytes; 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) stream.next_out = reinterpret_cast<uint8*>(output); 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) stream.avail_out = max_output_bytes; 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Do a one-shot compression. This will return Z_STREAM_END only if |output| 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // is large enough to hold all compressed data. 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) result = deflate(&stream, Z_FINISH); 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool success = (result == Z_STREAM_END); 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!success) 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(2) << "deflate() failed. Result: " << result; 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) result = deflateEnd(&stream); 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(result == Z_OK || result == Z_DATA_ERROR); 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (success) 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *output_bytes = max_output_bytes - stream.avail_out; 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return success; 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool SerializeEvents(const LogMetadata& log_metadata, 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const FrameEventList& frame_events, 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const PacketEventList& packet_events, 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool compress, 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int max_output_bytes, 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) char* output, 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int* output_bytes) { 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_GT(max_output_bytes, 0); 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(output); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(output_bytes); 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (compress) { 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Allocate a reasonably large temp buffer to hold uncompressed data. 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<char[]> uncompressed_buffer(new char[kMaxUncompressedBytes]); 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int uncompressed_bytes; 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool success = DoSerializeEvents(log_metadata, 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) frame_events, 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) packet_events, 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kMaxUncompressedBytes, 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uncompressed_buffer.get(), 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &uncompressed_bytes); 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!success) 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return Compress(uncompressed_buffer.get(), 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uncompressed_bytes, 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_output_bytes, 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output, 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_bytes); 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return DoSerializeEvents(log_metadata, 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) frame_events, 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) packet_events, 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_output_bytes, 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output, 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_bytes); 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace cast 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace media 191