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 "chromecast/media/cma/test/frame_segmenter_for_test.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/port.h"
11 #include "base/run_loop.h"
12 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/demuxer.h"
15 #include "media/base/media_log.h"
16 #include "media/base/test_helpers.h"
17 #include "media/filters/ffmpeg_demuxer.h"
18 #include "media/filters/file_data_source.h"
19 #include "media/filters/h264_parser.h"
21 namespace chromecast
{
26 struct AudioFrameHeader
{
29 int sampling_frequency
;
33 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };
34 int mp3_sample_rate
[] = { 44100, 48000, 32000, 0 };
36 AudioFrameHeader
FindNextMp3Header(const uint8
* data
, size_t data_size
) {
38 AudioFrameHeader header
;
39 header
.frame_size
= 0;
43 for (size_t k
= 0; k
< data_size
- 4 && !found
; k
++) {
45 // syncword: 11111111111
48 if (!(data
[k
+ 0] == 0xff && (data
[k
+ 1] & 0xfe) == 0xfa))
51 int bitrate_index
= (data
[k
+ 2] >> 4);
52 if (bitrate_index
== 0 || bitrate_index
== 15) {
53 // Free size or bad bitrate => not supported.
57 int sample_rate_index
= (data
[k
+ 2] >> 2) & 0x3;
58 if (sample_rate_index
== 3)
62 ((1152 / 8) * mp3_bitrate
[bitrate_index
] * 1000) /
63 mp3_sample_rate
[sample_rate_index
];
64 if (data
[k
+ 2] & 0x2)
67 // Make sure the frame is complete.
68 if (k
+ frame_size
> data_size
)
71 if (k
+ frame_size
< data_size
- 3 &&
72 !(data
[k
+ frame_size
+ 0] == 0xff &&
73 (data
[k
+ frame_size
+ 1] & 0xfe) == 0xfa)) {
79 header
.frame_size
= frame_size
;
80 header
.sampling_frequency
= mp3_sample_rate
[sample_rate_index
];
87 BufferList
Mp3SegmenterForTest(const uint8
* data
, size_t data_size
) {
89 BufferList audio_frames
;
90 base::TimeDelta timestamp
;
93 AudioFrameHeader header
= FindNextMp3Header(&data
[offset
],
95 if (header
.frame_size
== 0)
98 header
.offset
+= offset
;
99 offset
= header
.offset
+ header
.frame_size
;
101 scoped_refptr
< ::media::DecoderBuffer
> buffer(
102 ::media::DecoderBuffer::CopyFrom(
103 &data
[header
.offset
], header
.frame_size
));
104 buffer
->set_timestamp(timestamp
);
105 audio_frames
.push_back(
106 scoped_refptr
<DecoderBufferBase
>(new DecoderBufferAdapter(buffer
)));
108 // 1152 samples in an MP3 frame.
109 timestamp
+= base::TimeDelta::FromMicroseconds(
110 (GG_UINT64_C(1152) * 1000 * 1000) / header
.sampling_frequency
);
115 struct H264AccessUnit
{
124 H264AccessUnit::H264AccessUnit()
131 BufferList
H264SegmenterForTest(const uint8
* data
, size_t data_size
) {
132 BufferList video_frames
;
133 std::list
<H264AccessUnit
> access_unit_list
;
134 H264AccessUnit access_unit
;
136 int prev_pic_order_cnt_lsb
= 0;
137 int pic_order_cnt_msb
= 0;
139 scoped_ptr
< ::media::H264Parser
> h264_parser(new ::media::H264Parser());
140 h264_parser
->SetStream(data
, data_size
);
145 ::media::H264NALU nalu
;
146 switch (h264_parser
->AdvanceToNextNALU(&nalu
)) {
147 case ::media::H264Parser::kOk
:
149 case ::media::H264Parser::kInvalidStream
:
150 case ::media::H264Parser::kUnsupportedStream
:
152 case ::media::H264Parser::kEOStream
:
159 // To get the NALU syncword offset, substract 3 or 4
160 // which corresponds to the possible syncword lengths.
161 size_t nalu_offset
= nalu
.data
- data
;
163 if (nalu_offset
> 0 && data
[nalu_offset
-1] == 0)
166 switch (nalu
.nal_unit_type
) {
167 case ::media::H264NALU::kAUD
: {
170 case ::media::H264NALU::kSPS
: {
172 if (h264_parser
->ParseSPS(&sps_id
) != ::media::H264Parser::kOk
)
174 if (access_unit
.has_vcl
) {
175 access_unit
.size
= nalu_offset
- access_unit
.offset
;
176 access_unit_list
.push_back(access_unit
);
177 access_unit
= H264AccessUnit();
178 access_unit
.offset
= nalu_offset
;
182 case ::media::H264NALU::kPPS
: {
184 if (h264_parser
->ParsePPS(&pps_id
) != ::media::H264Parser::kOk
)
186 if (access_unit
.has_vcl
) {
187 access_unit
.size
= nalu_offset
- access_unit
.offset
;
188 access_unit_list
.push_back(access_unit
);
189 access_unit
= H264AccessUnit();
190 access_unit
.offset
= nalu_offset
;
194 case ::media::H264NALU::kIDRSlice
:
195 case ::media::H264NALU::kNonIDRSlice
: {
196 ::media::H264SliceHeader shdr
;
197 if (h264_parser
->ParseSliceHeader(nalu
, &shdr
) !=
198 ::media::H264Parser::kOk
) {
201 const ::media::H264PPS
* pps
=
202 h264_parser
->GetPPS(shdr
.pic_parameter_set_id
);
205 const ::media::H264SPS
* sps
=
206 h264_parser
->GetSPS(pps
->seq_parameter_set_id
);
208 // Very simplified way to segment H264.
209 // This assumes only 1 VCL NALU per access unit.
210 if (access_unit
.has_vcl
) {
211 access_unit
.size
= nalu_offset
- access_unit
.offset
;
212 access_unit_list
.push_back(access_unit
);
213 access_unit
= H264AccessUnit();
214 access_unit
.offset
= nalu_offset
;
217 access_unit
.has_vcl
= true;
219 // Support only explicit POC so far.
220 if (sps
->pic_order_cnt_type
!= 0) {
221 LOG(WARNING
) << "Unsupported pic_order_cnt_type";
224 int diff_pic_order_cnt_lsb
=
225 shdr
.pic_order_cnt_lsb
- prev_pic_order_cnt_lsb
;
226 int max_pic_order_cnt_lsb
=
227 1 << (sps
->log2_max_pic_order_cnt_lsb_minus4
+ 4);
228 if (diff_pic_order_cnt_lsb
< 0 &&
229 diff_pic_order_cnt_lsb
<= -max_pic_order_cnt_lsb
/ 2) {
230 pic_order_cnt_msb
+= max_pic_order_cnt_lsb
;
231 } else if (diff_pic_order_cnt_lsb
> 0 &&
232 diff_pic_order_cnt_lsb
> max_pic_order_cnt_lsb
/ 2) {
233 pic_order_cnt_msb
-= max_pic_order_cnt_lsb
;
235 access_unit
.poc
= pic_order_cnt_msb
+ shdr
.pic_order_cnt_lsb
;
236 prev_pic_order_cnt_lsb
= shdr
.pic_order_cnt_lsb
;
244 // Emit the last access unit.
245 if (access_unit
.has_vcl
) {
246 access_unit
.size
= data_size
- access_unit
.offset
;
247 access_unit_list
.push_back(access_unit
);
250 // Create the list of buffers.
251 // Totally arbitrary decision: assume a delta POC of 1 is 20ms (50Hz field
253 base::TimeDelta poc_duration
= base::TimeDelta::FromMilliseconds(20);
254 for (std::list
<H264AccessUnit
>::iterator it
= access_unit_list
.begin();
255 it
!= access_unit_list
.end(); ++it
) {
256 scoped_refptr
< ::media::DecoderBuffer
> buffer(
257 ::media::DecoderBuffer::CopyFrom(&data
[it
->offset
], it
->size
));
258 buffer
->set_timestamp(it
->poc
* poc_duration
);
259 video_frames
.push_back(
260 scoped_refptr
<DecoderBufferBase
>(new DecoderBufferAdapter(buffer
)));
266 void OnEncryptedMediaInitData(::media::EmeInitDataType init_data_type
,
267 const std::vector
<uint8
>& init_data
) {
268 LOG(FATAL
) << "Unexpected test failure: file is encrypted.";
271 void OnNewBuffer(BufferList
* buffer_list
,
272 const base::Closure
& finished_cb
,
273 ::media::DemuxerStream::Status status
,
274 const scoped_refptr
< ::media::DecoderBuffer
>& buffer
) {
275 CHECK_EQ(status
, ::media::DemuxerStream::kOk
);
278 buffer_list
->push_back(new DecoderBufferAdapter(buffer
));
282 class FakeDemuxerHost
: public ::media::DemuxerHost
{
284 // DemuxerHost implementation.
285 void AddBufferedTimeRange(base::TimeDelta start
,
286 base::TimeDelta end
) override
{}
287 void SetDuration(base::TimeDelta duration
) override
{}
288 void OnDemuxerError(::media::PipelineStatus error
) override
{
289 LOG(FATAL
) << "OnDemuxerError: " << error
;
291 void AddTextStream(::media::DemuxerStream
* text_stream
,
292 const ::media::TextTrackConfig
& config
) override
{
294 void RemoveTextStream(::media::DemuxerStream
* text_stream
) override
{
298 DemuxResult::DemuxResult() {
301 DemuxResult::~DemuxResult() {
304 DemuxResult
FFmpegDemuxForTest(const base::FilePath
& filepath
,
306 FakeDemuxerHost fake_demuxer_host
;
307 ::media::FileDataSource data_source
;
308 CHECK(data_source
.Initialize(filepath
));
310 ::media::FFmpegDemuxer
demuxer(
311 base::MessageLoopProxy::current(), &data_source
,
312 base::Bind(&OnEncryptedMediaInitData
), new ::media::MediaLog());
313 ::media::WaitableMessageLoopEvent init_event
;
314 demuxer
.Initialize(&fake_demuxer_host
,
315 init_event
.GetPipelineStatusCB(),
317 init_event
.RunAndWaitForStatus(::media::PIPELINE_OK
);
319 ::media::DemuxerStream
* stream
= demuxer
.GetStream(
320 audio
? ::media::DemuxerStream::AUDIO
: ::media::DemuxerStream::VIDEO
);
323 DemuxResult demux_result
;
325 demux_result
.audio_config
= stream
->audio_decoder_config();
327 demux_result
.video_config
= stream
->video_decoder_config();
330 bool end_of_stream
= false;
331 while (!end_of_stream
) {
332 base::RunLoop run_loop
;
333 stream
->Read(base::Bind(&OnNewBuffer
,
334 base::Unretained(&demux_result
.frames
),
335 run_loop
.QuitClosure()));
337 CHECK(!demux_result
.frames
.empty());
338 end_of_stream
= demux_result
.frames
.back()->end_of_stream();
346 } // namespace chromecast