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
;
67 mkvparser::EBMLHeader header
;
69 if (header
.Parse(reader
, pos
) < 0) {
70 rewind_and_reset(webm_ctx
, vpx_ctx
);
74 mkvparser::Segment
* segment
;
75 if (mkvparser::Segment::CreateInstance(reader
, pos
, segment
)) {
76 rewind_and_reset(webm_ctx
, vpx_ctx
);
79 webm_ctx
->segment
= segment
;
80 if (segment
->Load() < 0) {
81 rewind_and_reset(webm_ctx
, vpx_ctx
);
85 const mkvparser::Tracks
*const tracks
= segment
->GetTracks();
86 const mkvparser::VideoTrack
* video_track
= NULL
;
87 for (unsigned long i
= 0; i
< tracks
->GetTracksCount(); ++i
) {
88 const mkvparser::Track
* const track
= tracks
->GetTrackByIndex(i
);
89 if (track
->GetType() == mkvparser::Track::kVideo
) {
90 video_track
= static_cast<const mkvparser::VideoTrack
*>(track
);
91 webm_ctx
->video_track_index
= track
->GetNumber();
96 if (video_track
== NULL
) {
97 rewind_and_reset(webm_ctx
, vpx_ctx
);
101 if (!strncmp(video_track
->GetCodecId(), "V_VP8", 5)) {
102 vpx_ctx
->fourcc
= VP8_FOURCC
;
103 } else if (!strncmp(video_track
->GetCodecId(), "V_VP9", 5)) {
104 vpx_ctx
->fourcc
= VP9_FOURCC
;
106 rewind_and_reset(webm_ctx
, vpx_ctx
);
110 vpx_ctx
->framerate
.denominator
= 0;
111 vpx_ctx
->framerate
.numerator
= 0;
112 vpx_ctx
->width
= static_cast<uint32_t>(video_track
->GetWidth());
113 vpx_ctx
->height
= static_cast<uint32_t>(video_track
->GetHeight());
115 get_first_cluster(webm_ctx
);
120 int webm_read_frame(struct WebmInputContext
*webm_ctx
,
122 size_t *bytes_in_buffer
,
123 size_t *buffer_size
) {
124 mkvparser::Segment
*const segment
=
125 reinterpret_cast<mkvparser::Segment
*>(webm_ctx
->segment
);
126 const mkvparser::Cluster
* cluster
=
127 reinterpret_cast<const mkvparser::Cluster
*>(webm_ctx
->cluster
);
128 const mkvparser::Block
*block
=
129 reinterpret_cast<const mkvparser::Block
*>(webm_ctx
->block
);
130 const mkvparser::BlockEntry
*block_entry
=
131 reinterpret_cast<const mkvparser::BlockEntry
*>(webm_ctx
->block_entry
);
132 bool block_entry_eos
= false;
135 bool get_new_block
= false;
136 if (block_entry
== NULL
&& !block_entry_eos
) {
137 status
= cluster
->GetFirst(block_entry
);
138 get_new_block
= true;
139 } else if (block_entry_eos
|| block_entry
->EOS()) {
140 cluster
= segment
->GetNext(cluster
);
141 if (cluster
== NULL
|| cluster
->EOS()) {
142 *bytes_in_buffer
= 0;
145 status
= cluster
->GetFirst(block_entry
);
146 block_entry_eos
= false;
147 get_new_block
= true;
148 } else if (block
== NULL
||
149 webm_ctx
->block_frame_index
== block
->GetFrameCount() ||
150 block
->GetTrackNumber() != webm_ctx
->video_track_index
) {
151 status
= cluster
->GetNext(block_entry
, block_entry
);
152 if (block_entry
== NULL
|| block_entry
->EOS()) {
153 block_entry_eos
= true;
156 get_new_block
= true;
162 block
= block_entry
->GetBlock();
163 webm_ctx
->block_frame_index
= 0;
165 } while (block
->GetTrackNumber() != webm_ctx
->video_track_index
||
168 webm_ctx
->cluster
= cluster
;
169 webm_ctx
->block_entry
= block_entry
;
170 webm_ctx
->block
= block
;
172 const mkvparser::Block::Frame
& frame
=
173 block
->GetFrame(webm_ctx
->block_frame_index
);
174 ++webm_ctx
->block_frame_index
;
175 if (frame
.len
> static_cast<long>(*buffer_size
)) {
177 *buffer
= new uint8_t[frame
.len
];
178 if (*buffer
== NULL
) {
181 *buffer_size
= frame
.len
;
182 webm_ctx
->buffer
= *buffer
;
184 *bytes_in_buffer
= frame
.len
;
185 webm_ctx
->timestamp_ns
= block
->GetTime(cluster
);
186 webm_ctx
->is_key_frame
= block
->IsKey();
188 mkvparser::MkvReader
*const reader
=
189 reinterpret_cast<mkvparser::MkvReader
*>(webm_ctx
->reader
);
190 return frame
.Read(reader
, *buffer
) ? -1 : 0;
193 int webm_guess_framerate(struct WebmInputContext
*webm_ctx
,
194 struct VpxInputContext
*vpx_ctx
) {
196 uint8_t *buffer
= NULL
;
197 size_t bytes_in_buffer
= 0;
198 size_t buffer_size
= 0;
199 while (webm_ctx
->timestamp_ns
< 1000000000 && i
< 50) {
200 if (webm_read_frame(webm_ctx
, &buffer
, &bytes_in_buffer
, &buffer_size
)) {
205 vpx_ctx
->framerate
.numerator
= (i
- 1) * 1000000;
206 vpx_ctx
->framerate
.denominator
=
207 static_cast<int>(webm_ctx
->timestamp_ns
/ 1000);
210 get_first_cluster(webm_ctx
);
211 webm_ctx
->block
= NULL
;
212 webm_ctx
->block_entry
= NULL
;
213 webm_ctx
->block_frame_index
= 0;
214 webm_ctx
->timestamp_ns
= 0;
219 void webm_free(struct WebmInputContext
*webm_ctx
) {