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;
46 void get_first_cluster(struct WebmInputContext
*const webm_ctx
) {
47 mkvparser::Segment
*const segment
=
48 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
49 const mkvparser::Cluster
*const cluster
= segment
->GetFirst();
50 webm_ctx
->cluster
= cluster
;
53 void rewind_and_reset(struct WebmInputContext
*const webm_ctx
,
54 struct VpxInputContext
*const vpx_ctx
) {
55 rewind(vpx_ctx
->file
);
61 int file_is_webm(struct WebmInputContext
*webm_ctx
,
62 struct VpxInputContext
*vpx_ctx
) {
63 mkvparser::MkvReader
*const reader
= new mkvparser::MkvReader(vpx_ctx
->file
);
64 webm_ctx
->reader
= reader
;
66 mkvparser::EBMLHeader header
;
68 if (header
.Parse(reader
, pos
) < 0) {
69 rewind_and_reset(webm_ctx
, vpx_ctx
);
73 mkvparser::Segment
* segment
;
74 if (mkvparser::Segment::CreateInstance(reader
, pos
, segment
)) {
75 rewind_and_reset(webm_ctx
, vpx_ctx
);
78 webm_ctx
->segment
= segment
;
79 if (segment
->Load() < 0) {
80 rewind_and_reset(webm_ctx
, vpx_ctx
);
84 const mkvparser::Tracks
*const tracks
= segment
->GetTracks();
85 const mkvparser::VideoTrack
* video_track
= NULL
;
86 for (unsigned long i
= 0; i
< tracks
->GetTracksCount(); ++i
) {
87 const mkvparser::Track
* const track
= tracks
->GetTrackByIndex(i
);
88 if (track
->GetType() == mkvparser::Track::kVideo
) {
89 video_track
= static_cast<const mkvparser::VideoTrack
*>(track
);
90 webm_ctx
->video_track_index
= track
->GetNumber();
95 if (video_track
== NULL
) {
96 rewind_and_reset(webm_ctx
, vpx_ctx
);
100 if (!strncmp(video_track
->GetCodecId(), "V_VP8", 5)) {
101 vpx_ctx
->fourcc
= VP8_FOURCC
;
102 } else if (!strncmp(video_track
->GetCodecId(), "V_VP9", 5)) {
103 vpx_ctx
->fourcc
= VP9_FOURCC
;
105 rewind_and_reset(webm_ctx
, vpx_ctx
);
109 vpx_ctx
->framerate
.denominator
= 0;
110 vpx_ctx
->framerate
.numerator
= 0;
111 vpx_ctx
->width
= static_cast<uint32_t>(video_track
->GetWidth());
112 vpx_ctx
->height
= static_cast<uint32_t>(video_track
->GetHeight());
114 get_first_cluster(webm_ctx
);
119 int webm_read_frame(struct WebmInputContext
*webm_ctx
,
121 size_t *bytes_in_buffer
,
122 size_t *buffer_size
) {
123 mkvparser::Segment
*const segment
=
124 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
125 const mkvparser::Cluster
* cluster
=
126 reinterpret_cast<const mkvparser::Cluster
*>(webm_ctx
->cluster
);
127 const mkvparser::Block
*block
=
128 reinterpret_cast<const mkvparser::Block
*>(webm_ctx
->block
);
129 const mkvparser::BlockEntry
*block_entry
=
130 reinterpret_cast<const mkvparser::BlockEntry
*>(webm_ctx
->block_entry
);
131 bool block_entry_eos
= false;
134 bool get_new_block
= false;
135 if (block_entry
== NULL
&& !block_entry_eos
) {
136 status
= cluster
->GetFirst(block_entry
);
137 get_new_block
= true;
138 } else if (block_entry_eos
|| block_entry
->EOS()) {
139 cluster
= segment
->GetNext(cluster
);
140 if (cluster
== NULL
|| cluster
->EOS()) {
141 *bytes_in_buffer
= 0;
144 status
= cluster
->GetFirst(block_entry
);
145 block_entry_eos
= false;
146 get_new_block
= true;
147 } else if (block
== NULL
||
148 webm_ctx
->block_frame_index
== block
->GetFrameCount() ||
149 block
->GetTrackNumber() != webm_ctx
->video_track_index
) {
150 status
= cluster
->GetNext(block_entry
, block_entry
);
151 if (block_entry
== NULL
|| block_entry
->EOS()) {
152 block_entry_eos
= true;
155 get_new_block
= true;
161 block
= block_entry
->GetBlock();
162 webm_ctx
->block_frame_index
= 0;
164 } while (block
->GetTrackNumber() != webm_ctx
->video_track_index
||
167 webm_ctx
->cluster
= cluster
;
168 webm_ctx
->block_entry
= block_entry
;
169 webm_ctx
->block
= block
;
171 const mkvparser::Block::Frame
& frame
=
172 block
->GetFrame(webm_ctx
->block_frame_index
);
173 ++webm_ctx
->block_frame_index
;
174 if (frame
.len
> static_cast<long>(*buffer_size
)) {
176 *buffer
= new uint8_t[frame
.len
];
177 if (*buffer
== NULL
) {
180 *buffer_size
= frame
.len
;
181 webm_ctx
->buffer
= *buffer
;
183 *bytes_in_buffer
= frame
.len
;
184 webm_ctx
->timestamp_ns
= block
->GetTime(cluster
);
186 mkvparser::MkvReader
*const reader
=
187 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
188 return frame
.Read(reader
, *buffer
) ? -1 : 0;
191 int webm_guess_framerate(struct WebmInputContext
*webm_ctx
,
192 struct VpxInputContext
*vpx_ctx
) {
194 uint8_t *buffer
= NULL
;
195 size_t bytes_in_buffer
= 0;
196 size_t buffer_size
= 0;
197 while (webm_ctx
->timestamp_ns
< 1000000000 && i
< 50) {
198 if (webm_read_frame(webm_ctx
, &buffer
, &bytes_in_buffer
, &buffer_size
)) {
203 vpx_ctx
->framerate
.numerator
= (i
- 1) * 1000000;
204 vpx_ctx
->framerate
.denominator
=
205 static_cast<int>(webm_ctx
->timestamp_ns
/ 1000);
208 get_first_cluster(webm_ctx
);
209 webm_ctx
->block
= NULL
;
210 webm_ctx
->block_entry
= NULL
;
211 webm_ctx
->block_frame_index
= 0;
212 webm_ctx
->timestamp_ns
= 0;
217 void webm_free(struct WebmInputContext
*webm_ctx
) {