2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
11 #include "./webmdec.h"
16 #include "third_party/libwebm/mkvparser.hpp"
17 #include "third_party/libwebm/mkvreader.hpp"
21 void reset(struct WebmInputContext
*const webm_ctx
) {
22 if (webm_ctx
->reader
!= NULL
) {
23 mkvparser::MkvReader
*const reader
=
24 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
27 if (webm_ctx
->segment
!= NULL
) {
28 mkvparser::Segment
*const segment
=
29 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
32 if (webm_ctx
->buffer
!= NULL
) {
33 delete[] webm_ctx
->buffer
;
35 webm_ctx
->reader
= NULL
;
36 webm_ctx
->segment
= NULL
;
37 webm_ctx
->buffer
= NULL
;
38 webm_ctx
->cluster
= NULL
;
39 webm_ctx
->block_entry
= NULL
;
40 webm_ctx
->block
= NULL
;
41 webm_ctx
->block_frame_index
= 0;
42 webm_ctx
->video_track_index
= 0;
43 webm_ctx
->timestamp_ns
= 0;
44 webm_ctx
->is_key_frame
= false;
47 void get_first_cluster(struct WebmInputContext
*const webm_ctx
) {
48 mkvparser::Segment
*const segment
=
49 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
50 const mkvparser::Cluster
*const cluster
= segment
->GetFirst();
51 webm_ctx
->cluster
= cluster
;
54 void rewind_and_reset(struct WebmInputContext
*const webm_ctx
,
55 struct VpxInputContext
*const vpx_ctx
) {
56 rewind(vpx_ctx
->file
);
62 int file_is_webm(struct WebmInputContext
*webm_ctx
,
63 struct VpxInputContext
*vpx_ctx
) {
64 mkvparser::MkvReader
*const reader
= new mkvparser::MkvReader(vpx_ctx
->file
);
65 webm_ctx
->reader
= reader
;
66 webm_ctx
->reached_eos
= 0;
68 mkvparser::EBMLHeader header
;
70 if (header
.Parse(reader
, pos
) < 0) {
71 rewind_and_reset(webm_ctx
, vpx_ctx
);
75 mkvparser::Segment
* segment
;
76 if (mkvparser::Segment::CreateInstance(reader
, pos
, segment
)) {
77 rewind_and_reset(webm_ctx
, vpx_ctx
);
80 webm_ctx
->segment
= segment
;
81 if (segment
->Load() < 0) {
82 rewind_and_reset(webm_ctx
, vpx_ctx
);
86 const mkvparser::Tracks
*const tracks
= segment
->GetTracks();
87 const mkvparser::VideoTrack
* video_track
= NULL
;
88 for (unsigned long i
= 0; i
< tracks
->GetTracksCount(); ++i
) {
89 const mkvparser::Track
* const track
= tracks
->GetTrackByIndex(i
);
90 if (track
->GetType() == mkvparser::Track::kVideo
) {
91 video_track
= static_cast<const mkvparser::VideoTrack
*>(track
);
92 webm_ctx
->video_track_index
= track
->GetNumber();
97 if (video_track
== NULL
|| video_track
->GetCodecId() == NULL
) {
98 rewind_and_reset(webm_ctx
, vpx_ctx
);
102 if (!strncmp(video_track
->GetCodecId(), "V_VP8", 5)) {
103 vpx_ctx
->fourcc
= VP8_FOURCC
;
104 } else if (!strncmp(video_track
->GetCodecId(), "V_VP9", 5)) {
105 vpx_ctx
->fourcc
= VP9_FOURCC
;
106 } else if (!strncmp(video_track
->GetCodecId(), "V_VP10", 6)) {
107 vpx_ctx
->fourcc
= VP10_FOURCC
;
109 rewind_and_reset(webm_ctx
, vpx_ctx
);
113 vpx_ctx
->framerate
.denominator
= 0;
114 vpx_ctx
->framerate
.numerator
= 0;
115 vpx_ctx
->width
= static_cast<uint32_t>(video_track
->GetWidth());
116 vpx_ctx
->height
= static_cast<uint32_t>(video_track
->GetHeight());
118 get_first_cluster(webm_ctx
);
123 int webm_read_frame(struct WebmInputContext
*webm_ctx
,
125 size_t *bytes_in_buffer
,
126 size_t *buffer_size
) {
127 // This check is needed for frame parallel decoding, in which case this
128 // function could be called even after it has reached end of input stream.
129 if (webm_ctx
->reached_eos
) {
132 mkvparser::Segment
*const segment
=
133 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
134 const mkvparser::Cluster
* cluster
=
135 reinterpret_cast<const mkvparser::Cluster
*>(webm_ctx
->cluster
);
136 const mkvparser::Block
*block
=
137 reinterpret_cast<const mkvparser::Block
*>(webm_ctx
->block
);
138 const mkvparser::BlockEntry
*block_entry
=
139 reinterpret_cast<const mkvparser::BlockEntry
*>(webm_ctx
->block_entry
);
140 bool block_entry_eos
= false;
143 bool get_new_block
= false;
144 if (block_entry
== NULL
&& !block_entry_eos
) {
145 status
= cluster
->GetFirst(block_entry
);
146 get_new_block
= true;
147 } else if (block_entry_eos
|| block_entry
->EOS()) {
148 cluster
= segment
->GetNext(cluster
);
149 if (cluster
== NULL
|| cluster
->EOS()) {
150 *bytes_in_buffer
= 0;
151 webm_ctx
->reached_eos
= 1;
154 status
= cluster
->GetFirst(block_entry
);
155 block_entry_eos
= false;
156 get_new_block
= true;
157 } else if (block
== NULL
||
158 webm_ctx
->block_frame_index
== block
->GetFrameCount() ||
159 block
->GetTrackNumber() != webm_ctx
->video_track_index
) {
160 status
= cluster
->GetNext(block_entry
, block_entry
);
161 if (block_entry
== NULL
|| block_entry
->EOS()) {
162 block_entry_eos
= true;
165 get_new_block
= true;
171 block
= block_entry
->GetBlock();
172 webm_ctx
->block_frame_index
= 0;
174 } while (block
->GetTrackNumber() != webm_ctx
->video_track_index
||
177 webm_ctx
->cluster
= cluster
;
178 webm_ctx
->block_entry
= block_entry
;
179 webm_ctx
->block
= block
;
181 const mkvparser::Block::Frame
& frame
=
182 block
->GetFrame(webm_ctx
->block_frame_index
);
183 ++webm_ctx
->block_frame_index
;
184 if (frame
.len
> static_cast<long>(*buffer_size
)) {
186 *buffer
= new uint8_t[frame
.len
];
187 if (*buffer
== NULL
) {
190 *buffer_size
= frame
.len
;
191 webm_ctx
->buffer
= *buffer
;
193 *bytes_in_buffer
= frame
.len
;
194 webm_ctx
->timestamp_ns
= block
->GetTime(cluster
);
195 webm_ctx
->is_key_frame
= block
->IsKey();
197 mkvparser::MkvReader
*const reader
=
198 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
199 return frame
.Read(reader
, *buffer
) ? -1 : 0;
202 int webm_guess_framerate(struct WebmInputContext
*webm_ctx
,
203 struct VpxInputContext
*vpx_ctx
) {
205 uint8_t *buffer
= NULL
;
206 size_t bytes_in_buffer
= 0;
207 size_t buffer_size
= 0;
208 while (webm_ctx
->timestamp_ns
< 1000000000 && i
< 50) {
209 if (webm_read_frame(webm_ctx
, &buffer
, &bytes_in_buffer
, &buffer_size
)) {
214 vpx_ctx
->framerate
.numerator
= (i
- 1) * 1000000;
215 vpx_ctx
->framerate
.denominator
=
216 static_cast<int>(webm_ctx
->timestamp_ns
/ 1000);
219 get_first_cluster(webm_ctx
);
220 webm_ctx
->block
= NULL
;
221 webm_ctx
->block_entry
= NULL
;
222 webm_ctx
->block_frame_index
= 0;
223 webm_ctx
->timestamp_ns
= 0;
224 webm_ctx
->reached_eos
= 0;
229 void webm_free(struct WebmInputContext
*webm_ctx
) {