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/mkvparser.h"
17 #include "third_party/libwebm/mkvparser/mkvreader.h"
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 *buffer_size
) {
126 // This check is needed for frame parallel decoding, in which case this
127 // function could be called even after it has reached end of input stream.
128 if (webm_ctx
->reached_eos
) {
131 mkvparser::Segment
*const segment
=
132 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
133 const mkvparser::Cluster
* cluster
=
134 reinterpret_cast<const mkvparser::Cluster
*>(webm_ctx
->cluster
);
135 const mkvparser::Block
*block
=
136 reinterpret_cast<const mkvparser::Block
*>(webm_ctx
->block
);
137 const mkvparser::BlockEntry
*block_entry
=
138 reinterpret_cast<const mkvparser::BlockEntry
*>(webm_ctx
->block_entry
);
139 bool block_entry_eos
= false;
142 bool get_new_block
= false;
143 if (block_entry
== NULL
&& !block_entry_eos
) {
144 status
= cluster
->GetFirst(block_entry
);
145 get_new_block
= true;
146 } else if (block_entry_eos
|| block_entry
->EOS()) {
147 cluster
= segment
->GetNext(cluster
);
148 if (cluster
== NULL
|| cluster
->EOS()) {
150 webm_ctx
->reached_eos
= 1;
153 status
= cluster
->GetFirst(block_entry
);
154 block_entry_eos
= false;
155 get_new_block
= true;
156 } else if (block
== NULL
||
157 webm_ctx
->block_frame_index
== block
->GetFrameCount() ||
158 block
->GetTrackNumber() != webm_ctx
->video_track_index
) {
159 status
= cluster
->GetNext(block_entry
, block_entry
);
160 if (block_entry
== NULL
|| block_entry
->EOS()) {
161 block_entry_eos
= true;
164 get_new_block
= true;
166 if (status
|| block_entry
== NULL
) {
170 block
= block_entry
->GetBlock();
171 webm_ctx
->block_frame_index
= 0;
173 } while (block
->GetTrackNumber() != webm_ctx
->video_track_index
||
176 webm_ctx
->cluster
= cluster
;
177 webm_ctx
->block_entry
= block_entry
;
178 webm_ctx
->block
= block
;
180 const mkvparser::Block::Frame
& frame
=
181 block
->GetFrame(webm_ctx
->block_frame_index
);
182 ++webm_ctx
->block_frame_index
;
183 if (frame
.len
> static_cast<long>(*buffer_size
)) {
185 *buffer
= new uint8_t[frame
.len
];
186 if (*buffer
== NULL
) {
189 webm_ctx
->buffer
= *buffer
;
191 *buffer_size
= frame
.len
;
192 webm_ctx
->timestamp_ns
= block
->GetTime(cluster
);
193 webm_ctx
->is_key_frame
= block
->IsKey();
195 mkvparser::MkvReader
*const reader
=
196 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
197 return frame
.Read(reader
, *buffer
) ? -1 : 0;
200 int webm_guess_framerate(struct WebmInputContext
*webm_ctx
,
201 struct VpxInputContext
*vpx_ctx
) {
203 uint8_t *buffer
= NULL
;
204 size_t buffer_size
= 0;
205 while (webm_ctx
->timestamp_ns
< 1000000000 && i
< 50) {
206 if (webm_read_frame(webm_ctx
, &buffer
, &buffer_size
)) {
211 vpx_ctx
->framerate
.numerator
= (i
- 1) * 1000000;
212 vpx_ctx
->framerate
.denominator
=
213 static_cast<int>(webm_ctx
->timestamp_ns
/ 1000);
216 get_first_cluster(webm_ctx
);
217 webm_ctx
->block
= NULL
;
218 webm_ctx
->block_entry
= NULL
;
219 webm_ctx
->block_frame_index
= 0;
220 webm_ctx
->timestamp_ns
= 0;
221 webm_ctx
->reached_eos
= 0;
226 void webm_free(struct WebmInputContext
*webm_ctx
) {