Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / cast / logging / log_serializer.cc
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 // The serialization format is as follows:
6 //   16-bit integer describing the following LogMetadata proto size in bytes.
7 //   The LogMetadata proto.
8 //   32-bit integer describing number of frame events.
9 //   (The following repeated for number of frame events):
10 //     16-bit integer describing the following AggregatedFrameEvent proto size
11 //         in bytes.
12 //     The AggregatedFrameEvent proto.
13 //   32-bit integer describing number of packet events.
14 //   (The following repeated for number of packet events):
15 //     16-bit integer describing the following AggregatedPacketEvent proto
16 //         size in bytes.
17 //     The AggregatedPacketEvent proto.
18
19 #include "media/cast/logging/log_serializer.h"
20
21 #include "base/big_endian.h"
22 #include "base/logging.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "third_party/zlib/zlib.h"
25
26 namespace media {
27 namespace cast {
28
29 namespace {
30
31 using media::cast::proto::AggregatedFrameEvent;
32 using media::cast::proto::AggregatedPacketEvent;
33 using media::cast::proto::LogMetadata;
34
35 // Use 30MB of temp buffer to hold uncompressed data if |compress| is true.
36 const int kMaxUncompressedBytes = 30 * 1000 * 1000;
37
38 // The maximum allowed size per serialized proto.
39 const int kMaxSerializedProtoBytes = (1 << 16) - 1;
40 bool DoSerializeEvents(const LogMetadata& metadata,
41                        const FrameEventList& frame_events,
42                        const PacketEventList& packet_events,
43                        const int max_output_bytes,
44                        char* output,
45                        int* output_bytes) {
46   base::BigEndianWriter writer(output, max_output_bytes);
47
48   int proto_size = metadata.ByteSize();
49   DCHECK(proto_size <= kMaxSerializedProtoBytes);
50   if (!writer.WriteU16(static_cast<uint16>(proto_size)))
51     return false;
52   if (!metadata.SerializeToArray(writer.ptr(), writer.remaining()))
53     return false;
54   if (!writer.Skip(proto_size))
55     return false;
56
57   RtpTimestamp prev_rtp_timestamp = 0;
58   for (media::cast::FrameEventList::const_iterator it = frame_events.begin();
59        it != frame_events.end();
60        ++it) {
61     media::cast::proto::AggregatedFrameEvent frame_event(**it);
62
63     // Adjust relative RTP timestamp so that it is relative to previous frame,
64     // rather than relative to first RTP timestamp.
65     // This is done to improve encoding size.
66     RtpTimestamp old_relative_rtp_timestamp =
67         frame_event.relative_rtp_timestamp();
68     frame_event.set_relative_rtp_timestamp(
69         old_relative_rtp_timestamp - prev_rtp_timestamp);
70     prev_rtp_timestamp = old_relative_rtp_timestamp;
71
72     proto_size = frame_event.ByteSize();
73     DCHECK(proto_size <= kMaxSerializedProtoBytes);
74
75     // Write size of the proto, then write the proto.
76     if (!writer.WriteU16(static_cast<uint16>(proto_size)))
77       return false;
78     if (!frame_event.SerializeToArray(writer.ptr(), writer.remaining()))
79       return false;
80     if (!writer.Skip(proto_size))
81       return false;
82   }
83
84   // Write packet events.
85   prev_rtp_timestamp = 0;
86   for (media::cast::PacketEventList::const_iterator it = packet_events.begin();
87        it != packet_events.end();
88        ++it) {
89     media::cast::proto::AggregatedPacketEvent packet_event(**it);
90     RtpTimestamp old_relative_rtp_timestamp =
91         packet_event.relative_rtp_timestamp();
92     packet_event.set_relative_rtp_timestamp(
93         old_relative_rtp_timestamp - prev_rtp_timestamp);
94     prev_rtp_timestamp = old_relative_rtp_timestamp;
95
96     proto_size = packet_event.ByteSize();
97     DCHECK(proto_size <= kMaxSerializedProtoBytes);
98
99     // Write size of the proto, then write the proto.
100     if (!writer.WriteU16(static_cast<uint16>(proto_size)))
101       return false;
102     if (!packet_event.SerializeToArray(writer.ptr(), writer.remaining()))
103       return false;
104     if (!writer.Skip(proto_size))
105       return false;
106   }
107
108   *output_bytes = max_output_bytes - writer.remaining();
109   return true;
110 }
111
112 bool Compress(char* uncompressed_buffer,
113               int uncompressed_bytes,
114               int max_output_bytes,
115               char* output,
116               int* output_bytes) {
117   z_stream stream = {0};
118   int result = deflateInit2(&stream,
119                             Z_DEFAULT_COMPRESSION,
120                             Z_DEFLATED,
121                             // 16 is added to produce a gzip header + trailer.
122                             MAX_WBITS + 16,
123                             8,  // memLevel = 8 is default.
124                             Z_DEFAULT_STRATEGY);
125   DCHECK_EQ(Z_OK, result);
126
127   stream.next_in = reinterpret_cast<uint8*>(uncompressed_buffer);
128   stream.avail_in = uncompressed_bytes;
129   stream.next_out = reinterpret_cast<uint8*>(output);
130   stream.avail_out = max_output_bytes;
131
132   // Do a one-shot compression. This will return Z_STREAM_END only if |output|
133   // is large enough to hold all compressed data.
134   result = deflate(&stream, Z_FINISH);
135   bool success = (result == Z_STREAM_END);
136
137   if (!success)
138     DVLOG(2) << "deflate() failed. Result: " << result;
139
140   result = deflateEnd(&stream);
141   DCHECK(result == Z_OK || result == Z_DATA_ERROR);
142
143   if (success)
144     *output_bytes = max_output_bytes - stream.avail_out;
145
146   return success;
147 }
148
149 }  // namespace
150
151 bool SerializeEvents(const LogMetadata& log_metadata,
152                      const FrameEventList& frame_events,
153                      const PacketEventList& packet_events,
154                      bool compress,
155                      int max_output_bytes,
156                      char* output,
157                      int* output_bytes) {
158   DCHECK_GT(max_output_bytes, 0);
159   DCHECK(output);
160   DCHECK(output_bytes);
161
162   if (compress) {
163     // Allocate a reasonably large temp buffer to hold uncompressed data.
164     scoped_ptr<char[]> uncompressed_buffer(new char[kMaxUncompressedBytes]);
165     int uncompressed_bytes;
166     bool success = DoSerializeEvents(log_metadata,
167                                      frame_events,
168                                      packet_events,
169                                      kMaxUncompressedBytes,
170                                      uncompressed_buffer.get(),
171                                      &uncompressed_bytes);
172     if (!success)
173       return false;
174     return Compress(uncompressed_buffer.get(),
175                     uncompressed_bytes,
176                     max_output_bytes,
177                     output,
178                     output_bytes);
179   } else {
180     return DoSerializeEvents(log_metadata,
181                              frame_events,
182                              packet_events,
183                              max_output_bytes,
184                              output,
185                              output_bytes);
186   }
187 }
188
189 }  // namespace cast
190 }  // namespace media