2 * Copyright (c) 2005, David McPaul based on avi_reader copyright (c) 2004 Marcus Overhagen
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <StopWatch.h>
30 #include <ByteOrder.h>
31 #include <InterfaceDefs.h>
32 #include <MediaFormats.h>
33 #include "RawFormats.h"
35 #include "mov_reader.h"
37 //#define TRACE_MOV_READER
38 #ifdef TRACE_MOV_READER
44 #define ERROR(a...) fprintf(stderr, a)
60 uint32 bytes_per_sec_rate
;
61 uint32 bytes_per_sec_scale
;
68 uint32 frames_per_sec_rate
;
69 uint32 frames_per_sec_scale
;
73 movReader::movReader()
76 TRACE("movReader::movReader\n");
79 movReader::~movReader()
85 movReader::Copyright()
87 return "mov_reader & libMOV, " B_UTF8_COPYRIGHT
" by David McPaul";
91 movReader::Sniff(int32
*streamCount
)
93 TRACE("movReader::Sniff\n");
95 BPositionIO
*pos_io_source
;
97 pos_io_source
= dynamic_cast<BPositionIO
*>(Reader::Source());
99 TRACE("movReader::Sniff: not a BPositionIO\n");
103 if (!MOVFileReader::IsSupported(pos_io_source
)) {
104 TRACE("movReader::Sniff: unsupported file type\n");
108 TRACE("movReader::Sniff: this stream seems to be supported\n");
110 theFileReader
= new MOVFileReader(pos_io_source
);
111 if (B_OK
!= theFileReader
->ParseFile()) {
112 ERROR("movReader::Sniff: error parsing file\n");
116 *streamCount
= theFileReader
->getStreamCount();
121 movReader::GetFileFormatInfo(media_file_format
*mff
)
123 mff
->capabilities
= media_file_format::B_READABLE
124 | media_file_format::B_KNOWS_ENCODED_VIDEO
125 | media_file_format::B_KNOWS_ENCODED_AUDIO
126 | media_file_format::B_IMPERFECTLY_SEEKABLE
;
127 mff
->family
= B_QUICKTIME_FORMAT_FAMILY
;
129 strcpy(mff
->mime_type
, "video/quicktime");
130 strcpy(mff
->file_extension
, "mov");
131 strcpy(mff
->short_name
, "MOV");
132 strcpy(mff
->pretty_name
, "Quicktime (MOV) file format");
136 movReader::AllocateCookie(int32 streamNumber
, void **_cookie
)
140 mov_cookie
*cookie
= new mov_cookie
;
143 cookie
->stream
= streamNumber
;
145 cookie
->buffer_size
= 0;
146 cookie
->frame_pos
= 0;
148 BMediaFormats formats
;
149 media_format
*format
= &cookie
->format
;
150 media_format_description description
;
152 if (theFileReader
->IsActive(cookie
->stream
) == false) {
153 ERROR("movReader::AllocateCookie: stream %d is not active\n", cookie
->stream
);
158 const mov_stream_header
*stream_header
;
159 stream_header
= theFileReader
->StreamFormat(cookie
->stream
);
160 if (!stream_header
) {
161 ERROR("movReader::AllocateCookie: stream %d has no header\n", cookie
->stream
);
166 TRACE("movReader::AllocateCookie: stream %ld (%s)\n", streamNumber
, theFileReader
->IsAudio(cookie
->stream
) ? "audio" : theFileReader
->IsVideo(cookie
->stream
) ? "video" : "unknown");
168 if (theFileReader
->IsAudio(cookie
->stream
)) {
169 const AudioMetaData
*audio_format
= theFileReader
->AudioFormat(cookie
->stream
);
171 ERROR("movReader::AllocateCookie: audio stream %d has no format\n", cookie
->stream
);
176 codecID
= B_BENDIAN_TO_HOST_INT32(audio_format
->compression
);
178 cookie
->frame_count
= theFileReader
->getAudioFrameCount(cookie
->stream
);
179 cookie
->duration
= theFileReader
->getAudioDuration(cookie
->stream
);
181 cookie
->audio
= true;
182 cookie
->byte_pos
= 0;
184 if (stream_header
->scale
&& stream_header
->rate
) {
185 cookie
->bytes_per_sec_rate
= stream_header
->rate
* audio_format
->SampleSize
* audio_format
->NoOfChannels
/ 8;
186 cookie
->bytes_per_sec_scale
= stream_header
->scale
;
187 cookie
->frames_per_sec_rate
= stream_header
->rate
;
188 cookie
->frames_per_sec_scale
= stream_header
->scale
;
189 TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n", cookie
->bytes_per_sec_rate
, cookie
->bytes_per_sec_scale
);
190 } else if (stream_header
->rate
) {
191 cookie
->bytes_per_sec_rate
= stream_header
->rate
* audio_format
->SampleSize
* audio_format
->NoOfChannels
/ 8;
192 cookie
->bytes_per_sec_scale
= 1;
193 cookie
->frames_per_sec_rate
= stream_header
->rate
;
194 cookie
->frames_per_sec_scale
= 1;
195 TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n", cookie
->bytes_per_sec_rate
, cookie
->bytes_per_sec_scale
);
196 } else if (audio_format
->BufferSize
) {
197 cookie
->bytes_per_sec_rate
= audio_format
->BufferSize
;
198 cookie
->bytes_per_sec_scale
= 1;
199 cookie
->frames_per_sec_rate
= audio_format
->BufferSize
* 8 / audio_format
->SampleSize
/ audio_format
->NoOfChannels
;
200 cookie
->frames_per_sec_scale
= 1;
201 TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using PacketSize)\n", cookie
->bytes_per_sec_rate
, cookie
->bytes_per_sec_scale
);
203 cookie
->bytes_per_sec_rate
= 128000;
204 cookie
->bytes_per_sec_scale
= 8;
205 cookie
->frames_per_sec_rate
= 16000;
206 cookie
->frames_per_sec_scale
= 1;
207 TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using fallback)\n", cookie
->bytes_per_sec_rate
, cookie
->bytes_per_sec_scale
);
210 if ((audio_format
->compression
== AUDIO_NONE
) ||
211 (audio_format
->compression
== AUDIO_RAW
) ||
212 (audio_format
->compression
== AUDIO_TWOS1
) ||
213 (audio_format
->compression
== AUDIO_TWOS2
)) {
214 description
.family
= B_BEOS_FORMAT_FAMILY
;
215 description
.u
.beos
.format
= B_BEOS_FORMAT_RAW_AUDIO
;
216 if (B_OK
!= formats
.GetFormatFor(description
, format
)) {
217 format
->type
= B_MEDIA_RAW_AUDIO
;
220 format
->u
.raw_audio
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
221 format
->u
.raw_audio
.channel_count
= audio_format
->NoOfChannels
;
223 format
->u
.raw_audio
.byte_order
= B_MEDIA_BIG_ENDIAN
;
225 if (audio_format
->SampleSize
<= 8)
226 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_UINT8
;
227 else if (audio_format
->SampleSize
<= 16)
228 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT16
;
229 else if (audio_format
->SampleSize
<= 24)
230 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT24
;
231 else if (audio_format
->SampleSize
<= 32)
232 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT32
;
234 ERROR("movReader::AllocateCookie: unhandled bits per sample %d\n", audio_format
->SampleSize
);
238 if (audio_format
->compression
== AUDIO_TWOS1
) {
239 if (audio_format
->SampleSize
<= 8) {
240 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT8
;
241 } else if (audio_format
->SampleSize
<= 16) {
242 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT16
;
243 format
->u
.raw_audio
.byte_order
= B_MEDIA_BIG_ENDIAN
;
246 if (audio_format
->compression
== AUDIO_TWOS2
) {
247 if (audio_format
->SampleSize
<= 8) {
248 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT8
;
249 } else if (audio_format
->SampleSize
<= 16) {
250 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT16
;
251 format
->u
.raw_audio
.byte_order
= B_MEDIA_LITTLE_ENDIAN
;
255 format
->u
.raw_audio
.buffer_size
= stream_header
->suggested_buffer_size
;
258 description
.family
= B_QUICKTIME_FORMAT_FAMILY
;
259 description
.u
.quicktime
.codec
= audio_format
->compression
;
260 if (B_OK
!= formats
.GetFormatFor(description
, format
)) {
261 format
->type
= B_MEDIA_ENCODED_AUDIO
;
264 format
->u
.raw_audio
.byte_order
= B_MEDIA_BIG_ENDIAN
;
266 if (audio_format
->SampleSize
<= 8)
267 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_UINT8
;
268 else if (audio_format
->SampleSize
<= 16)
269 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT16
;
270 else if (audio_format
->SampleSize
<= 24)
271 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT24
;
272 else if (audio_format
->SampleSize
<= 32)
273 format
->u
.raw_audio
.format
= B_AUDIO_FORMAT_INT32
;
275 ERROR("movReader::AllocateCookie: unhandled bits per sample %d\n", audio_format
->SampleSize
);
279 format
->u
.encoded_audio
.frame_size
= audio_format
->FrameSize
;
280 format
->u
.encoded_audio
.output
.buffer_size
= audio_format
->BufferSize
;
282 TRACE("compression ");
284 switch (audio_format
->compression
) {
287 format
->u
.raw_audio
.format
|= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE
;
288 format
->u
.encoded_audio
.bit_rate
= 8 * cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
289 format
->u
.encoded_audio
.output
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
290 format
->u
.encoded_audio
.output
.channel_count
= audio_format
->NoOfChannels
;
292 case AUDIO_INTEL_PCM17
:
293 TRACE("INTEL PCM\n");
294 format
->u
.encoded_audio
.bit_rate
= 8 * cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
295 format
->u
.encoded_audio
.output
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
296 format
->u
.encoded_audio
.output
.channel_count
= audio_format
->NoOfChannels
;
298 case AUDIO_MPEG3_CBR
:
300 format
->u
.encoded_audio
.bit_rate
= 8 * cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
301 format
->u
.encoded_audio
.output
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
302 format
->u
.encoded_audio
.output
.channel_count
= audio_format
->NoOfChannels
;
306 format
->u
.encoded_audio
.bit_rate
= audio_format
->BitRate
;
307 format
->u
.encoded_audio
.output
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;;
308 format
->u
.encoded_audio
.output
.channel_count
= audio_format
->NoOfChannels
;
311 TRACE("OTHER %s\n",(char *)(&codecID
));
312 format
->u
.encoded_audio
.bit_rate
= 8 * cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
313 format
->u
.encoded_audio
.output
.frame_rate
= cookie
->frames_per_sec_rate
/ cookie
->frames_per_sec_scale
;
314 format
->u
.encoded_audio
.output
.channel_count
= audio_format
->NoOfChannels
;
319 TRACE("Audio NoOfChannels %d, SampleSize %d, SampleRate %f, FrameSize %ld\n",audio_format
->NoOfChannels
, audio_format
->SampleSize
, audio_format
->SampleRate
, audio_format
->FrameSize
);
321 TRACE("Audio frame_rate %f, channel_count %ld, format %ld, buffer_size %ld, frame_size %ld, bit_rate %f\n",
322 format
->u
.encoded_audio
.output
.frame_rate
, format
->u
.encoded_audio
.output
.channel_count
, format
->u
.encoded_audio
.output
.format
,format
->u
.encoded_audio
.output
.buffer_size
, format
->u
.encoded_audio
.frame_size
, format
->u
.encoded_audio
.bit_rate
);
324 // Some codecs have additional setup data that they need, put it in metadata
325 size_t size
= audio_format
->VOLSize
;
326 const void *data
= audio_format
->theVOL
;
328 TRACE("VOL SIZE %ld\n", size
);
329 format
->SetMetaData(data
, size
);
333 // Put the codeid in the user data in case someone wants it
334 format
->user_data_type
= B_CODEC_TYPE_INFO
;
335 *(uint32
*)format
->user_data
= codecID
; format
->user_data
[4] = 0;
341 if (theFileReader
->IsVideo(cookie
->stream
)) {
342 const VideoMetaData
*video_format
= theFileReader
->VideoFormat(cookie
->stream
);
344 ERROR("movReader::AllocateCookie: video stream %d has no format\n", cookie
->stream
);
349 codecID
= B_BENDIAN_TO_HOST_INT32(video_format
->compression
);
351 cookie
->audio
= false;
352 cookie
->line_count
= theFileReader
->MovMainHeader()->height
;
354 if (stream_header
->scale
&& stream_header
->rate
) {
355 cookie
->frames_per_sec_rate
= stream_header
->rate
;
356 cookie
->frames_per_sec_scale
= stream_header
->scale
;
357 TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n", cookie
->frames_per_sec_rate
, cookie
->frames_per_sec_scale
);
358 } else if (theFileReader
->MovMainHeader()->micro_sec_per_frame
) {
359 cookie
->frames_per_sec_rate
= 1000000;
360 cookie
->frames_per_sec_scale
= theFileReader
->MovMainHeader()->micro_sec_per_frame
;
361 TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using micro_sec_per_frame)\n", cookie
->frames_per_sec_rate
, cookie
->frames_per_sec_scale
);
363 cookie
->frames_per_sec_rate
= 25;
364 cookie
->frames_per_sec_scale
= 1;
365 TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using fallback)\n", cookie
->frames_per_sec_rate
, cookie
->frames_per_sec_scale
);
368 cookie
->frame_count
= stream_header
->length
;
369 cookie
->duration
= (cookie
->frame_count
* (int64
)cookie
->frames_per_sec_scale
* 1000000LL) / cookie
->frames_per_sec_rate
;
371 TRACE("frame_count %Ld\n", cookie
->frame_count
);
372 TRACE("duration %.6f (%Ld)\n", cookie
->duration
/ 1E6
, cookie
->duration
);
373 TRACE("compression %s\n", (char *)(&codecID
));
375 description
.family
= B_QUICKTIME_FORMAT_FAMILY
;
376 if (stream_header
->fourcc_handler
== 'ekaf' || stream_header
->fourcc_handler
== 0) // 'fake' or 0 fourcc => used compression id
377 description
.u
.quicktime
.codec
= video_format
->compression
;
379 description
.u
.quicktime
.codec
= video_format
->compression
;
380 if (B_OK
!= formats
.GetFormatFor(description
, format
))
381 format
->type
= B_MEDIA_ENCODED_VIDEO
;
383 format
->user_data_type
= B_CODEC_TYPE_INFO
;
384 *(uint32
*)format
->user_data
= description
.u
.quicktime
.codec
; format
->user_data
[4] = 0;
386 format
->u
.encoded_video
.max_bit_rate
= 8 * theFileReader
->MovMainHeader()->max_bytes_per_sec
;
387 format
->u
.encoded_video
.avg_bit_rate
= format
->u
.encoded_video
.max_bit_rate
/ 2; // XXX fix this
388 format
->u
.encoded_video
.output
.field_rate
= cookie
->frames_per_sec_rate
/ (float)cookie
->frames_per_sec_scale
;
389 format
->u
.encoded_video
.output
.interlace
= 1; // 1: progressive
390 format
->u
.encoded_video
.output
.first_active
= 0;
391 format
->u
.encoded_video
.output
.last_active
= cookie
->line_count
- 1;
392 format
->u
.encoded_video
.output
.orientation
= B_VIDEO_TOP_LEFT_RIGHT
;
393 format
->u
.encoded_video
.output
.pixel_width_aspect
= 1;
394 format
->u
.encoded_video
.output
.pixel_height_aspect
= 1;
395 format
->u
.encoded_video
.output
.display
.line_width
= theFileReader
->MovMainHeader()->width
;
396 format
->u
.encoded_video
.output
.display
.line_count
= cookie
->line_count
;
397 format
->u
.encoded_video
.output
.display
.bytes_per_row
= 0; // format->u.encoded_video.output.display.line_width * 4;
398 format
->u
.encoded_video
.output
.display
.pixel_offset
= 0;
399 format
->u
.encoded_video
.output
.display
.line_offset
= 0;
400 format
->u
.encoded_video
.output
.display
.flags
= 0;
402 TRACE("max_bit_rate %.3f\n", format
->u
.encoded_video
.max_bit_rate
);
403 TRACE("field_rate %.3f\n", format
->u
.encoded_video
.output
.field_rate
);
405 // Some decoders need additional metadata passed via a special Atom
406 size_t size
= video_format
->VOLSize
;
407 const void *data
= video_format
->theVOL
;
409 TRACE("VOL SIZE %ld\n", size
);
410 format
->SetMetaData(data
, size
);
414 // Put the codeid in the user data in case someone wants it
415 format
->user_data_type
= B_CODEC_TYPE_INFO
;
416 *(uint32
*)format
->user_data
= codecID
; format
->user_data
[4] = 0;
428 movReader::FreeCookie(void *_cookie
)
430 mov_cookie
*cookie
= (mov_cookie
*)_cookie
;
432 delete [] cookie
->buffer
;
440 movReader::GetStreamInfo(void *_cookie
, int64
*frameCount
, bigtime_t
*duration
,
441 media_format
*format
, const void **infoBuffer
, size_t *infoSize
)
443 mov_cookie
*cookie
= (mov_cookie
*)_cookie
;
446 *frameCount
= cookie
->frame_count
;
447 *duration
= cookie
->duration
;
448 *format
= cookie
->format
;
450 // Copy metadata to infoBuffer
451 if (theFileReader
->IsVideo(cookie
->stream
)) {
452 const VideoMetaData
*video_format
= theFileReader
->VideoFormat(cookie
->stream
);
453 *infoBuffer
= video_format
->theVOL
;
454 *infoSize
= video_format
->VOLSize
;
456 const AudioMetaData
*audio_format
= theFileReader
->AudioFormat(cookie
->stream
);
457 *infoBuffer
= audio_format
->theVOL
;
458 *infoSize
= audio_format
->VOLSize
;
467 movReader::Seek(void *cookie
,
469 int64
*frame
, bigtime_t
*time
)
471 // Seek to the requested frame
473 mov_cookie
*movcookie
= (mov_cookie
*)cookie
;
475 if (seekTo
& B_MEDIA_SEEK_TO_TIME
) {
476 // frame = (time * rate) / fps / 1000000LL
477 *frame
= ((*time
* movcookie
->frames_per_sec_rate
) / (int64
)movcookie
->frames_per_sec_scale
) / 1000000LL;
478 movcookie
->frame_pos
= *frame
;
479 TRACE("Time %Ld to Frame %Ld\n",*time
, *frame
);
482 if (seekTo
& B_MEDIA_SEEK_TO_FRAME
) {
483 // time = frame * 1000000LL * fps / rate
484 *time
= (*frame
* 1000000LL * (int64
)movcookie
->frames_per_sec_scale
) / movcookie
->frames_per_sec_rate
;
485 movcookie
->frame_pos
= *frame
;
486 TRACE("Frame %Ld to Time %Ld\n", *frame
, *time
);
489 TRACE("movReader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
490 (seekTo
& B_MEDIA_SEEK_TO_TIME
) ? " B_MEDIA_SEEK_TO_TIME" : "",
491 (seekTo
& B_MEDIA_SEEK_TO_FRAME
) ? " B_MEDIA_SEEK_TO_FRAME" : "",
492 (seekTo
& B_MEDIA_SEEK_CLOSEST_FORWARD
) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
493 (seekTo
& B_MEDIA_SEEK_CLOSEST_BACKWARD
) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
500 movReader::FindKeyFrame(void* cookie
, uint32 flags
,
501 int64
* frame
, bigtime_t
* time
)
503 // Find the nearest keyframe to the given time or frame.
505 mov_cookie
*movcookie
= (mov_cookie
*)cookie
;
507 bool keyframe
= false;
509 if (flags
& B_MEDIA_SEEK_TO_TIME
) {
510 // convert time to frame as we seek by frame
511 // frame = (time * rate) / fps / 1000000LL
512 *frame
= ((*time
* movcookie
->frames_per_sec_rate
) / (int64
)movcookie
->frames_per_sec_scale
) / 1000000LL;
515 TRACE("movReader::FindKeyFrame: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
516 (flags
& B_MEDIA_SEEK_TO_TIME
) ? " B_MEDIA_SEEK_TO_TIME" : "",
517 (flags
& B_MEDIA_SEEK_TO_FRAME
) ? " B_MEDIA_SEEK_TO_FRAME" : "",
518 (flags
& B_MEDIA_SEEK_CLOSEST_FORWARD
) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
519 (flags
& B_MEDIA_SEEK_CLOSEST_BACKWARD
) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
522 if (movcookie
->audio
) {
523 // Audio does not have keyframes? Or all audio frames are keyframes?
526 while (*frame
> 0 && *frame
<= movcookie
->frame_count
) {
527 keyframe
= theFileReader
->IsKeyFrame(movcookie
->stream
, *frame
);
532 if (flags
& B_MEDIA_SEEK_CLOSEST_BACKWARD
) {
539 // We consider frame 0 to be a keyframe.
540 if (!keyframe
&& *frame
> 0) {
541 TRACE("Did NOT find keyframe at frame %Ld\n",*frame
);
542 return B_LAST_BUFFER_ERROR
;
546 // convert frame found to time
547 // time = frame * 1000000LL * fps / rate
548 *time
= (*frame
* 1000000LL * (int64
)movcookie
->frames_per_sec_scale
) / movcookie
->frames_per_sec_rate
;
550 TRACE("Found keyframe at frame %Ld time %Ld\n",*frame
,*time
);
556 movReader::GetNextChunk(void *_cookie
,
557 const void **chunkBuffer
, size_t *chunkSize
,
558 media_header
*mediaHeader
)
560 mov_cookie
*cookie
= (mov_cookie
*)_cookie
;
562 int64 start
; uint32 size
; bool keyframe
; uint32 chunkFrameCount
;
564 if (!theFileReader
->GetNextChunkInfo(cookie
->stream
, cookie
->frame_pos
, &start
, &size
, &keyframe
, &chunkFrameCount
))
565 return B_LAST_BUFFER_ERROR
;
567 if (cookie
->buffer_size
< size
) {
568 delete [] cookie
->buffer
;
569 cookie
->buffer_size
= (size
+ 15) & ~15;
570 cookie
->buffer
= new char [cookie
->buffer_size
];
574 TRACE("Audio stream %d: chunk %ld expected start %lld Size %ld key %d\n",cookie
->stream
, cookie
->frame_pos
, start
, size
, keyframe
);
575 mediaHeader
->type
= B_MEDIA_ENCODED_AUDIO
;
576 mediaHeader
->u
.encoded_audio
.buffer_flags
= keyframe
? B_MEDIA_KEY_FRAME
: 0;
578 // This will only work with raw audio I think.
579 mediaHeader
->start_time
= (cookie
->byte_pos
* 1000000LL * cookie
->bytes_per_sec_scale
) / cookie
->bytes_per_sec_rate
;
580 // TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using byte_pos\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos),mediaHeader->start_time);
582 // We should find the current frame position (ie first frame in chunk) then compute using fps
583 // cookie->frame_pos = theFileReader->getFirstFrameInChunk(cookie->stream,cookie->frame_pos);
584 mediaHeader
->start_time
= (cookie
->frame_pos
* 1000000LL * (int64
)cookie
->frames_per_sec_scale
) / cookie
->frames_per_sec_rate
;
585 // TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using frame_no %ld\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos),mediaHeader->start_time, cookie->frame_pos);
587 cookie
->byte_pos
+= size
;
589 TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie
->stream
, cookie
->frame_pos
, start
, size
, keyframe
);
590 mediaHeader
->start_time
= (cookie
->frame_pos
* 1000000LL * (int64
)cookie
->frames_per_sec_scale
) / cookie
->frames_per_sec_rate
;
591 mediaHeader
->type
= B_MEDIA_ENCODED_VIDEO
;
592 mediaHeader
->u
.encoded_video
.field_flags
= keyframe
? B_MEDIA_KEY_FRAME
: 0;
593 mediaHeader
->u
.encoded_video
.first_active_line
= 0;
594 mediaHeader
->u
.encoded_video
.line_count
= cookie
->line_count
;
597 cookie
->frame_pos
+= chunkFrameCount
;
598 TRACE("stream %d: start_time %.6f\n", cookie
->stream
, mediaHeader
->start_time
/ 1000000.0);
600 *chunkBuffer
= cookie
->buffer
;
602 return (int)size
== theFileReader
->Source()->ReadAt(start
, cookie
->buffer
, size
) ? B_OK
: B_LAST_BUFFER_ERROR
;
607 movReaderPlugin::NewReader()
609 return new movReader
;
613 MediaPlugin
*instantiate_plugin()
615 return new movReaderPlugin
;