2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
12 #include "./webmdec.h"
17 #include "third_party/libwebm/mkvparser/mkvparser.h"
18 #include "third_party/libwebm/mkvparser/mkvreader.h"
22 void reset(struct WebmInputContext
*const webm_ctx
) {
23 if (webm_ctx
->reader
!= NULL
) {
24 mkvparser::MkvReader
*const reader
=
25 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
28 if (webm_ctx
->segment
!= NULL
) {
29 mkvparser::Segment
*const segment
=
30 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
33 if (webm_ctx
->buffer
!= NULL
) {
34 delete[] webm_ctx
->buffer
;
36 webm_ctx
->reader
= NULL
;
37 webm_ctx
->segment
= NULL
;
38 webm_ctx
->buffer
= NULL
;
39 webm_ctx
->cluster
= NULL
;
40 webm_ctx
->block_entry
= NULL
;
41 webm_ctx
->block
= NULL
;
42 webm_ctx
->block_frame_index
= 0;
43 webm_ctx
->video_track_index
= 0;
44 webm_ctx
->timestamp_ns
= 0;
45 webm_ctx
->is_key_frame
= false;
48 void get_first_cluster(struct WebmInputContext
*const webm_ctx
) {
49 mkvparser::Segment
*const segment
=
50 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
51 const mkvparser::Cluster
*const cluster
= segment
->GetFirst();
52 webm_ctx
->cluster
= cluster
;
55 void rewind_and_reset(struct WebmInputContext
*const webm_ctx
,
56 struct AvxInputContext
*const aom_ctx
) {
57 rewind(aom_ctx
->file
);
63 int file_is_webm(struct WebmInputContext
*webm_ctx
,
64 struct AvxInputContext
*aom_ctx
) {
65 mkvparser::MkvReader
*const reader
= new mkvparser::MkvReader(aom_ctx
->file
);
66 webm_ctx
->reader
= reader
;
67 webm_ctx
->reached_eos
= 0;
69 mkvparser::EBMLHeader header
;
71 if (header
.Parse(reader
, pos
) < 0) {
72 rewind_and_reset(webm_ctx
, aom_ctx
);
76 mkvparser::Segment
*segment
;
77 if (mkvparser::Segment::CreateInstance(reader
, pos
, segment
)) {
78 rewind_and_reset(webm_ctx
, aom_ctx
);
81 webm_ctx
->segment
= segment
;
82 if (segment
->Load() < 0) {
83 rewind_and_reset(webm_ctx
, aom_ctx
);
87 const mkvparser::Tracks
*const tracks
= segment
->GetTracks();
88 const mkvparser::VideoTrack
*video_track
= NULL
;
89 for (unsigned long i
= 0; i
< tracks
->GetTracksCount(); ++i
) {
90 const mkvparser::Track
*const track
= tracks
->GetTrackByIndex(i
);
91 if (track
->GetType() == mkvparser::Track::kVideo
) {
92 video_track
= static_cast<const mkvparser::VideoTrack
*>(track
);
93 webm_ctx
->video_track_index
= static_cast<int>(track
->GetNumber());
98 if (video_track
== NULL
|| video_track
->GetCodecId() == NULL
) {
99 rewind_and_reset(webm_ctx
, aom_ctx
);
103 if (!strncmp(video_track
->GetCodecId(), "V_AV1", 5)) {
104 aom_ctx
->fourcc
= AV1_FOURCC
;
106 rewind_and_reset(webm_ctx
, aom_ctx
);
110 aom_ctx
->framerate
.denominator
= 0;
111 aom_ctx
->framerate
.numerator
= 0;
112 aom_ctx
->width
= static_cast<uint32_t>(video_track
->GetWidth());
113 aom_ctx
->height
= static_cast<uint32_t>(video_track
->GetHeight());
115 get_first_cluster(webm_ctx
);
120 int webm_read_frame(struct WebmInputContext
*webm_ctx
, uint8_t **buffer
,
121 size_t *buffer_size
) {
122 // This check is needed for frame parallel decoding, in which case this
123 // function could be called even after it has reached end of input stream.
124 if (webm_ctx
->reached_eos
) {
127 mkvparser::Segment
*const segment
=
128 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
129 const mkvparser::Cluster
*cluster
=
130 reinterpret_cast<const mkvparser::Cluster
*>(webm_ctx
->cluster
);
131 const mkvparser::Block
*block
=
132 reinterpret_cast<const mkvparser::Block
*>(webm_ctx
->block
);
133 const mkvparser::BlockEntry
*block_entry
=
134 reinterpret_cast<const mkvparser::BlockEntry
*>(webm_ctx
->block_entry
);
135 bool block_entry_eos
= false;
138 bool get_new_block
= false;
139 if (block_entry
== NULL
&& !block_entry_eos
) {
140 status
= cluster
->GetFirst(block_entry
);
141 get_new_block
= true;
142 } else if (block_entry_eos
|| block_entry
->EOS()) {
143 cluster
= segment
->GetNext(cluster
);
144 if (cluster
== NULL
|| cluster
->EOS()) {
146 webm_ctx
->reached_eos
= 1;
149 status
= cluster
->GetFirst(block_entry
);
150 block_entry_eos
= false;
151 get_new_block
= true;
152 } else if (block
== NULL
||
153 webm_ctx
->block_frame_index
== block
->GetFrameCount() ||
154 block
->GetTrackNumber() != webm_ctx
->video_track_index
) {
155 status
= cluster
->GetNext(block_entry
, block_entry
);
156 if (block_entry
== NULL
|| block_entry
->EOS()) {
157 block_entry_eos
= true;
160 get_new_block
= true;
162 if (status
|| block_entry
== NULL
) {
166 block
= block_entry
->GetBlock();
167 if (block
== NULL
) return -1;
168 webm_ctx
->block_frame_index
= 0;
170 } while (block_entry_eos
||
171 block
->GetTrackNumber() != webm_ctx
->video_track_index
);
173 webm_ctx
->cluster
= cluster
;
174 webm_ctx
->block_entry
= block_entry
;
175 webm_ctx
->block
= block
;
177 const mkvparser::Block::Frame
&frame
=
178 block
->GetFrame(webm_ctx
->block_frame_index
);
179 ++webm_ctx
->block_frame_index
;
180 if (frame
.len
> static_cast<long>(*buffer_size
)) {
182 *buffer
= new uint8_t[frame
.len
];
183 if (*buffer
== NULL
) {
186 webm_ctx
->buffer
= *buffer
;
188 *buffer_size
= frame
.len
;
189 webm_ctx
->timestamp_ns
= block
->GetTime(cluster
);
190 webm_ctx
->is_key_frame
= block
->IsKey();
192 mkvparser::MkvReader
*const reader
=
193 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
194 return frame
.Read(reader
, *buffer
) ? -1 : 0;
197 int webm_guess_framerate(struct WebmInputContext
*webm_ctx
,
198 struct AvxInputContext
*aom_ctx
) {
200 uint8_t *buffer
= NULL
;
201 size_t buffer_size
= 0;
202 while (webm_ctx
->timestamp_ns
< 1000000000 && i
< 50) {
203 if (webm_read_frame(webm_ctx
, &buffer
, &buffer_size
)) {
208 aom_ctx
->framerate
.numerator
= (i
- 1) * 1000000;
209 aom_ctx
->framerate
.denominator
=
210 static_cast<int>(webm_ctx
->timestamp_ns
/ 1000);
213 get_first_cluster(webm_ctx
);
214 webm_ctx
->block
= NULL
;
215 webm_ctx
->block_entry
= NULL
;
216 webm_ctx
->block_frame_index
= 0;
217 webm_ctx
->timestamp_ns
= 0;
218 webm_ctx
->reached_eos
= 0;
223 void webm_free(struct WebmInputContext
*webm_ctx
) { reset(webm_ctx
); }