Index: media/cast/test/log_encoder.cc |
diff --git a/media/cast/test/log_encoder.cc b/media/cast/test/log_encoder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6e795a2f84fec2c1ba972ec7aa2f139e8b2a176e |
--- /dev/null |
+++ b/media/cast/test/log_encoder.cc |
@@ -0,0 +1,405 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <algorithm> |
+#include <cstdio> |
+#include <iostream> |
+#include <string> |
+#include <sstream> |
+ |
+#include "base/rand_util.h" |
+#include "base/time/default_tick_clock.h" |
+#include "media/cast/cast_defines.h" |
+#include "media/cast/logging/logging_defines.h" |
+#include "media/cast/logging/logging_raw.h" |
+#include "media/cast/logging/proto/raw_events.pb.h" |
+#include "media/cast/test/fake_single_thread_task_runner.h" |
+#include "media/cast/logging/encoding_event_subscriber.h" |
+#include "net/base/big_endian.h" |
+#include "third_party/zlib/zlib.h" |
+ |
+using media::cast::CastLoggingEvent; |
+using media::cast::EncodingEventSubscriber; |
+using media::cast::FrameEvent; |
+using media::cast::FrameEventMap; |
+using media::cast::GenericEventMap; |
+using media::cast::LoggingRaw; |
+using media::cast::PacketEventMap; |
+using media::cast::proto::AggregatedFrameEvent; |
+using media::cast::proto::AggregatedGenericEvent; |
+using media::cast::proto::AggregatedPacketEvent; |
+using media::cast::proto::BasePacketEvent; |
+using media::cast::test::FakeSingleThreadTaskRunner; |
+ |
+const int kFps = 30; |
+const int kNumSeconds = 60 * 30; |
+ |
+const int kNumVideoFrames = kFps * kNumSeconds; |
+const CastLoggingEvent kVideoFrameEvents[] = { |
+ media::cast::kVideoFrameCaptured, |
+ media::cast::kVideoFrameReceived, |
+ media::cast::kVideoFrameSentToEncoder, |
+ media::cast::kVideoFrameEncoded, |
+ media::cast::kVideoFrameDecoded, |
+ media::cast::kVideoRenderDelay}; |
+ |
+// Average number of packets per video frame. |
+const int kNumPacketPerVideoFrame = 10; |
+ |
+const CastLoggingEvent kVideoPacketEvents[] = { |
+ media::cast::kPacketSentToPacer, |
+ media::cast::kPacketSentToNetwork, |
+ media::cast::kVideoPacketReceived}; |
+ |
+const CastLoggingEvent kOtherPacketEvents[] = { |
+ media::cast::kPacketRetransmitted, |
+ media::cast::kDuplicatePacketReceived}; |
+ |
+// 15 MB. |
+const int kCompressedMaxSize = 10 * 1000 * 1000; |
+// 100 MB. |
+const int kDecompressedMaxSize = 100 * 1000 * 1000; |
+ |
+// TODO(imcheng): All these should return bool indicating success. |
+void WriteTo(const FrameEventMap& frame_events, |
+ const PacketEventMap& packet_events, |
+ uint8* out, int out_buf_size, int* out_size); |
+void Compress(uint8* in, int in_buf_size, |
+ uint8* out, int out_buf_size, int* out_size); |
+void Decompress(uint8* in, int in_buf_size, |
+ uint8* out, int out_buf_size, int* out_size); |
+void ReadFrom(const uint8* in, const int in_size); |
+ |
+int main(int argc, char** argv) { |
+ EncodingEventSubscriber subscriber; |
+ LoggingRaw logging_raw; |
+ |
+ logging_raw.AddSubscriber(&subscriber); |
+ |
+ base::DefaultTickClock clock; |
+ base::TimeTicks base_now(clock.NowTicks()); |
+ base_now -= base::TimeDelta::FromSeconds(5400); |
+ printf("Time now: %ld\n", base_now.ToInternalValue()); |
+ |
+ printf("\n===========\n"); |
+ printf("Inserting frame events\n"); |
+ base::TimeTicks now(base_now); |
+ for (int i = 0; i < kNumVideoFrames; ++i) { |
+ now += base::TimeDelta::FromMilliseconds(33); |
+ base::TimeTicks base_now2(now); |
+ uint32 rtp_timestamp = media::cast::GetVideoRtpTimestamp(now); |
+ if (i < 5) { |
+ printf("Inserting first 5 event with RTP timestamp %u\n", rtp_timestamp); |
+ } |
+ if (kNumVideoFrames - i < 5) { |
+ printf("Inserting last 5 event with RTP timestamp %u\n", rtp_timestamp); |
+ } |
+ // Insert frame events for that frame. |
+ for (uint32 event_index = 0; event_index < arraysize(kVideoFrameEvents); |
+ ++event_index) { |
+ now += base::TimeDelta::FromMilliseconds(5); |
+ CastLoggingEvent type = kVideoFrameEvents[event_index]; |
+ if (type == media::cast::kVideoFrameEncoded) { |
+ int size = base::RandInt(32768, 65536); |
+ logging_raw.InsertFrameEventWithSize(now, type, rtp_timestamp, i, size); |
+ } else if (type == media::cast::kVideoRenderDelay) { |
+ base::TimeDelta delay( |
+ base::TimeDelta::FromMilliseconds(base::RandInt(0, 100))); |
+ logging_raw.InsertFrameEventWithDelay(now, type, rtp_timestamp, i, |
+ delay); |
+ } else { |
+ logging_raw.InsertFrameEvent(now, type, rtp_timestamp, i); |
+ } |
+ } |
+ now = base_now2; |
+ } |
+ |
+ printf("Inserting packet events\n"); |
+ now = base_now; |
+ for (int i = 0; i < kNumVideoFrames; ++i) { |
+ now += base::TimeDelta::FromMilliseconds(33); |
+ base::TimeTicks base_now2(now); |
+ uint32 rtp_timestamp = media::cast::GetVideoRtpTimestamp(now); |
+ |
+ // Insert packet events for that frame. |
+ for (int packet_id = 0; packet_id < kNumPacketPerVideoFrame; ++packet_id) { |
+ int size = base::RandInt(2048, 4096); |
+ for (uint32 event_index = 0; event_index < arraysize(kVideoPacketEvents); |
+ ++event_index) { |
+ now += base::TimeDelta::FromMilliseconds(1); |
+ CastLoggingEvent type = kVideoPacketEvents[event_index]; |
+ logging_raw.InsertPacketEvent(now, type, rtp_timestamp, i, packet_id, |
+ kNumPacketPerVideoFrame - 1, size); |
+ } |
+ |
+ // Randomly insert additional packet events. |
+ int rand = base::RandInt(0, 99); |
+ if (rand < 2) { |
+ now += base::TimeDelta::FromMilliseconds(1); |
+ logging_raw.InsertPacketEvent(now, media::cast::kPacketRetransmitted, |
+ rtp_timestamp, i, packet_id, |
+ kNumPacketPerVideoFrame - 1, size); |
+ } |
+ rand = base::RandInt(0, 99); |
+ if (rand < 2) { |
+ now += base::TimeDelta::FromMilliseconds(1); |
+ logging_raw.InsertPacketEvent( |
+ now, media::cast::kDuplicatePacketReceived, rtp_timestamp, i, |
+ packet_id, kNumPacketPerVideoFrame - 1, size); |
+ } |
+ } |
+ |
+ now = base_now2; |
+ } |
+ |
+ FrameEventMap frame_events; |
+ subscriber.GetFrameEventsAndReset(&frame_events); |
+ |
+ PacketEventMap packet_events; |
+ subscriber.GetPacketEventsAndReset(&packet_events); |
+ |
+ printf("Frame events map size: %lu\n", frame_events.size()); |
+ printf("Packet events map size: %lu\n", packet_events.size()); |
+ |
+ logging_raw.RemoveSubscriber(&subscriber); |
+ |
+ printf("\n===========\n"); |
+ printf("Performing serialization\n"); |
+ |
+ scoped_ptr<uint8[]> serialized_buf(new uint8[kDecompressedMaxSize]); |
+ int serialized_size; |
+ WriteTo(frame_events, packet_events, serialized_buf.get(), |
+ kDecompressedMaxSize, &serialized_size); |
+ printf("Serialized size: %d\n", serialized_size); |
+ |
+ printf("\n===========\n"); |
+ printf("Performing compression\n"); |
+ scoped_ptr<uint8[]> compressed_buf(new uint8[kCompressedMaxSize]); |
+ int compressed_size; |
+ Compress(serialized_buf.get(), serialized_size, compressed_buf.get(), |
+ kCompressedMaxSize, &compressed_size); |
+ printf("Compressed size: %d\n", compressed_size); |
+ serialized_buf.reset(); |
+ |
+ printf("\n===========\n"); |
+ printf("Performing decompression\n"); |
+ scoped_ptr<uint8[]> decompressed_buf(new uint8[kDecompressedMaxSize]); |
+ |
+ int decompressed_size; |
+ Decompress(compressed_buf.get(), compressed_size, |
+ decompressed_buf.get(), kDecompressedMaxSize, &decompressed_size); |
+ printf("Decompressed size: %d\n", decompressed_size); |
+ compressed_buf.reset(); |
+ |
+ printf("\n===========\n"); |
+ printf("Performing deserialization\n"); |
+ ReadFrom(decompressed_buf.get(), decompressed_size); |
+ |
+ printf("Done\n"); |
+ return 0; |
+} |
+ |
+void WriteTo(const FrameEventMap& frame_events, |
+ const PacketEventMap& packet_events, |
+ uint8* out, int out_buf_size, int* out_size) { |
+ |
+ // int index = 0; |
+ net::BigEndianWriter writer(out, out_buf_size); |
+ |
+ // Frame events - write size first, then write entries |
+ int frame_events_size = frame_events.size(); |
+ // memcpy(&out[index], &frame_events_size, sizeof(frame_events_size)); |
+ // index += sizeof(frame_events_size); |
+ bool success; |
+ success = writer.WriteU32(frame_events_size); |
+ // XXX: instead of DCHECKs, just return false. |
+ DCHECK(success); |
+ int i = 0; |
+ for (FrameEventMap::const_iterator it = frame_events.begin(); |
+ it != frame_events.end(); ++it) { |
+ int proto_size = it->second->ByteSize(); |
+ |
+ if (frame_events_size - i < 5) { |
+ printf("Serializing last 5 frame events, rtp ts: %u, %u\n", it->first, it->second->rtp_timestamp()); |
+ } |
+ i++; |
+ // Write size of the proto, then write the proto |
+ // memcpy(&out[index], &proto_size, sizeof(proto_size)); |
+ // index += sizeof(proto_size); |
+ success = writer.WriteU16(proto_size); |
+ DCHECK(success); |
+ |
+ // bool success = it->second->SerializeToArray(&out[index], out_size - index); |
+ // DCHECK(success); |
+ // index += proto_size; |
+ success = it->second->SerializeToArray(writer.ptr(), writer.remaining()); |
+ DCHECK(success); |
+ success = writer.Skip(proto_size); |
+ DCHECK(success); |
+ } |
+ |
+ int frame_event_serialized_size = (char*)writer.ptr() - (char*)out; |
+ printf("Encoded frame events size: %d\n", frame_event_serialized_size); |
+ |
+ // Write packet events |
+ int packet_event_size = packet_events.size(); |
+ // memcpy(&out[index], &packet_event_size, sizeof(packet_event_size)); |
+ // index += sizeof(packet_event_size); |
+ success = writer.WriteU32(packet_event_size); |
+ DCHECK(success); |
+ i = 0; |
+ for (PacketEventMap::const_iterator it = packet_events.begin(); |
+ it != packet_events.end(); ++it) { |
+ int proto_size = it->second->ByteSize(); |
+ if (packet_event_size - i < 5) { |
+ printf("Last 5 encoded packet size: %d, rtp timestamp: %u, %u\n", proto_size, it->first, it->second->rtp_timestamp()); |
+ } |
+ i++; |
+ // Write size of the proto, then write the proto |
+ // memcpy(&out[index], &proto_size, sizeof(proto_size)); |
+ // index += sizeof(proto_size); |
+ success = writer.WriteU16(proto_size); |
+ DCHECK(success); |
+ |
+ // bool success = it->second->SerializeToArray(&out[index], out_size - index); |
+ // index += proto_size; |
+ // DCHECK(success); |
+ success = it->second->SerializeToArray(writer.ptr(), writer.remaining()); |
+ DCHECK(success); |
+ success = writer.Skip(proto_size); |
+ DCHECK(success); |
+ } |
+ |
+ int packet_event_serialized_size = |
+ out_buf_size - writer.remaining() - frame_event_serialized_size; |
+ printf("Encoded packet events buff count: %d\n", |
+ packet_event_serialized_size); |
+ |
+ *out_size = out_buf_size - writer.remaining(); |
+} |
+ |
+void Compress(uint8* in, int in_buf_size, |
+ uint8* out, int out_buf_size, int* out_size) { |
+ z_stream stream = {0}; |
+ int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, |
+ // 16 is added to produce a gzip header + trailer. |
+ MAX_WBITS + 16, 8, // memLevel = 8 is default. |
+ Z_DEFAULT_STRATEGY); |
+ DCHECK_EQ(Z_OK, result); |
+ stream.next_in = in; |
+ stream.avail_in = in_buf_size; |
+ stream.next_out = out; |
+ stream.avail_out = out_buf_size; |
+ result = deflate(&stream, Z_FINISH); |
+ DCHECK_EQ(Z_STREAM_END, result) |
+ << ", maybe the output buffer isn't large enough?"; |
+ result = deflateEnd(&stream); |
+ DCHECK_EQ(Z_OK, result); |
+ |
+ *out_size = out_buf_size - stream.avail_out; |
+} |
+ |
+void Decompress(uint8* in, int in_buf_size, |
+ uint8* out, int out_buf_size, int* out_size) { |
+ z_stream stream = {0}; |
+ // 16 is added to read in gzip format. |
+ int result = inflateInit2(&stream, MAX_WBITS + 16); |
+ DCHECK_EQ(Z_OK, result); |
+ stream.next_in = in; |
+ stream.avail_in = in_buf_size; |
+ stream.next_out = out; |
+ stream.avail_out = out_buf_size; |
+ result = inflate(&stream, Z_FINISH); |
+ DCHECK_EQ(Z_STREAM_END, result) |
+ << ", maybe the output buffer isn't large enough?"; |
+ result = inflateEnd(&stream); |
+ DCHECK_EQ(Z_OK, result); |
+ |
+ // Trim to size. |
+ *out_size = out_buf_size - stream.avail_out; |
+} |
+ |
+void ReadFrom(const uint8* in, const int in_size) { |
+ //ArrayInputStream array_input_stream(&decompressed_string[0], |
+ // decompressed_string.size()); |
+ //CodedInputStream in(&array_input_stream); |
+ |
+// Reserve about 20MB. |
+ const int out_size = 20 * 1000 * 1000; |
+ scoped_ptr<uint8[]> out(new uint8[out_size]); |
+ bool success; |
+ |
+ //success = in.GetDirectBufferPointer( |
+ // reinterpret_cast<const void**>(&in_buffer), &buffer_size); |
+ //DCHECK(success); |
+ |
+ net::BigEndianReader reader(in, in_size); |
+ uint32 num_frame_events; |
+ //in_buffer = CodedInputStream::ReadLittleEndian32FromArray(in_buffer, |
+ // &num_frame_events); |
+ success = reader.ReadU32(&num_frame_events); |
+ DCHECK(success); |
+ |
+ printf("Read %u frame events\n", num_frame_events); |
+ |
+ for (uint32 i = 0; i < num_frame_events; i++) { |
+ uint16 proto_size = 0u; |
+ //in_buffer = |
+ // CodedInputStream::ReadLittleEndian32FromArray(in_buffer, &proto_size); |
+ success = reader.ReadU16(&proto_size); |
+ |
+ AggregatedFrameEvent frame_event; |
+ success = frame_event.ParseFromArray(reader.ptr(), proto_size); |
+ DCHECK(success) << ", " << i; |
+ reader.Skip(proto_size); |
+ //in_buffer += proto_size; |
+ if (i > num_frame_events - 5) { |
+ printf("Last 5 event:\n"); |
+ printf("RTP timestamp: %u\n", |
+ static_cast<uint32>(frame_event.rtp_timestamp())); |
+ printf("Event type size: %d\n", frame_event.event_type_size()); |
+ printf("Event timestamp micros size: %d\n", |
+ frame_event.event_timestamp_micros_size()); |
+ printf("Event encoded frame size: %d\n", |
+ frame_event.encoded_frame_size()); |
+ printf("Event delay millis: %d\n", frame_event.delay_millis()); |
+ } |
+ } |
+ |
+ uint32 num_packet_events = 0u; |
+ success = reader.ReadU32(&num_packet_events); |
+ DCHECK(success); |
+ //in_buffer = CodedInputStream::ReadLittleEndian32FromArray(in_buffer, |
+ // &num_packet_events); |
+ printf("Read %u packet events\n", num_packet_events); |
+ |
+ for (uint32 i = 0; i < num_packet_events; i++) { |
+ uint16 proto_size; |
+ //in_buffer = |
+ // CodedInputStream::ReadLittleEndian32FromArray(in_buffer, &proto_size); |
+ success = reader.ReadU16(&proto_size); |
+ DCHECK(success); |
+ |
+ AggregatedPacketEvent packet_event; |
+ success = packet_event.ParseFromArray(reader.ptr(), proto_size); |
+ DCHECK(success) << ", " << i; |
+ reader.Skip(proto_size); |
+ |
+ // in_buffer += proto_size; |
+ if (i > num_packet_events - 5) { |
+ printf("Last 5 event:\n"); |
+ printf("RTP timestamp: %u\n", packet_event.rtp_timestamp()); |
+ int base_size = packet_event.base_packet_event_size(); |
+ printf("Base packet event size: %d\n", base_size); |
+ int base_packet_index = base::RandInt(0, base_size - 1); |
+ printf("Getting base packet event %d\n", base_packet_index); |
+ BasePacketEvent base_packet_event = |
+ packet_event.base_packet_event(base_packet_index); |
+ printf("Base Event %d timestamp packet id: %d\n", base_packet_index, |
+ base_packet_event.packet_id()); |
+ printf("Base Event %d event type size: %d\n", base_packet_index, |
+ base_packet_event.event_type_size()); |
+ } |
+ } |
+} |