1/* 2 * Copyright (c) 2005, David McPaul based on avi_reader copyright (c) 2004 Marcus Overhagen 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 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. 13 * 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. 24 */ 25#include <stdio.h> 26#include <string.h> 27#include <malloc.h> 28#include <DataIO.h> 29#include <StopWatch.h> 30#include <ByteOrder.h> 31#include <InterfaceDefs.h> 32#include <MediaFormats.h> 33#include "RawFormats.h" 34 35#include "mov_reader.h" 36 37//#define TRACE_MOV_READER 38#ifdef TRACE_MOV_READER 39 #define TRACE printf 40#else 41 #define TRACE(a...) 42#endif 43 44#define ERROR(a...) fprintf(stderr, a) 45 46struct mov_cookie 47{ 48 unsigned stream; 49 char * buffer; 50 unsigned buffer_size; 51 52 int64 frame_count; 53 bigtime_t duration; 54 media_format format; 55 56 bool audio; 57 58 // audio only: 59 off_t byte_pos; 60 uint32 bytes_per_sec_rate; 61 uint32 bytes_per_sec_scale; 62 63 // video only: 64 uint32 line_count; 65 66 // Common 67 uint32 frame_pos; 68 uint32 frames_per_sec_rate; 69 uint32 frames_per_sec_scale; 70}; 71 72 73movReader::movReader() 74 : theFileReader(0) 75{ 76 TRACE("movReader::movReader\n"); 77} 78 79movReader::~movReader() 80{ 81 delete theFileReader; 82} 83 84const char * 85movReader::Copyright() 86{ 87 return "mov_reader & libMOV, " B_UTF8_COPYRIGHT " by David McPaul"; 88} 89 90status_t 91movReader::Sniff(int32 *streamCount) 92{ 93 TRACE("movReader::Sniff\n"); 94 95 BPositionIO *pos_io_source; 96 97 pos_io_source = dynamic_cast<BPositionIO *>(Reader::Source()); 98 if (!pos_io_source) { 99 TRACE("movReader::Sniff: not a BPositionIO\n"); 100 return B_ERROR; 101 } 102 103 if (!MOVFileReader::IsSupported(pos_io_source)) { 104 TRACE("movReader::Sniff: unsupported file type\n"); 105 return B_ERROR; 106 } 107 108 TRACE("movReader::Sniff: this stream seems to be supported\n"); 109 110 theFileReader = new MOVFileReader(pos_io_source); 111 if (B_OK != theFileReader->ParseFile()) { 112 ERROR("movReader::Sniff: error parsing file\n"); 113 return B_ERROR; 114 } 115 116 *streamCount = theFileReader->getStreamCount(); 117 return B_OK; 118} 119 120void 121movReader::GetFileFormatInfo(media_file_format *mff) 122{ 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; 128 mff->version = 100; 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"); 133} 134 135status_t 136movReader::AllocateCookie(int32 streamNumber, void **_cookie) 137{ 138 uint32 codecID; 139 140 mov_cookie *cookie = new mov_cookie; 141 *_cookie = cookie; 142 143 cookie->stream = streamNumber; 144 cookie->buffer = 0; 145 cookie->buffer_size = 0; 146 cookie->frame_pos = 0; 147 148 BMediaFormats formats; 149 media_format *format = &cookie->format; 150 media_format_description description; 151 152 if (theFileReader->IsActive(cookie->stream) == false) { 153 ERROR("movReader::AllocateCookie: stream %d is not active\n", cookie->stream); 154 delete cookie; 155 return B_ERROR; 156 } 157 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); 162 delete cookie; 163 return B_ERROR; 164 } 165 166 TRACE("movReader::AllocateCookie: stream %ld (%s)\n", streamNumber, theFileReader->IsAudio(cookie->stream) ? "audio" : theFileReader->IsVideo(cookie->stream) ? "video" : "unknown"); 167 168 if (theFileReader->IsAudio(cookie->stream)) { 169 const AudioMetaData *audio_format = theFileReader->AudioFormat(cookie->stream); 170 if (!audio_format) { 171 ERROR("movReader::AllocateCookie: audio stream %d has no format\n", cookie->stream); 172 delete cookie; 173 return B_ERROR; 174 } 175 176 codecID = B_BENDIAN_TO_HOST_INT32(audio_format->compression); 177 178 cookie->frame_count = theFileReader->getAudioFrameCount(cookie->stream); 179 cookie->duration = theFileReader->getAudioDuration(cookie->stream); 180 181 cookie->audio = true; 182 cookie->byte_pos = 0; 183 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); 202 } else { 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); 208 } 209 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; 218 } 219 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; 222 223 format->u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN; 224 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; 233 else { 234 ERROR("movReader::AllocateCookie: unhandled bits per sample %d\n", audio_format->SampleSize); 235 return B_ERROR; 236 } 237 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; 244 } 245 } 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; 252 } 253 } 254 255 format->u.raw_audio.buffer_size = stream_header->suggested_buffer_size; 256 } else { 257 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; 262 } 263 264 format->u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN; 265 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; 274 else { 275 ERROR("movReader::AllocateCookie: unhandled bits per sample %d\n", audio_format->SampleSize); 276 return B_ERROR; 277 } 278 279 format->u.encoded_audio.frame_size = audio_format->FrameSize; 280 format->u.encoded_audio.output.buffer_size = audio_format->BufferSize; 281 282 TRACE("compression "); 283 284 switch (audio_format->compression) { 285 case AUDIO_MS_PCM02: 286 TRACE("MS PCM02\n"); 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; 291 break; 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; 297 break; 298 case AUDIO_MPEG3_CBR: 299 TRACE("MP3\n"); 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; 303 break; 304 case AUDIO_IMA4: 305 TRACE("IMA4\n"); 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; 309 break; 310 default: 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; 315 break; 316 } 317 } 318 319 TRACE("Audio NoOfChannels %d, SampleSize %d, SampleRate %f, FrameSize %ld\n",audio_format->NoOfChannels, audio_format->SampleSize, audio_format->SampleRate, audio_format->FrameSize); 320 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); 323 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; 327 if (size > 0) { 328 TRACE("VOL SIZE %ld\n", size); 329 format->SetMetaData(data, size); 330 } 331 332 if (codecID != 0) { 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; 336 } 337 338 return B_OK; 339 } 340 341 if (theFileReader->IsVideo(cookie->stream)) { 342 const VideoMetaData *video_format = theFileReader->VideoFormat(cookie->stream); 343 if (!video_format) { 344 ERROR("movReader::AllocateCookie: video stream %d has no format\n", cookie->stream); 345 delete cookie; 346 return B_ERROR; 347 } 348 349 codecID = B_BENDIAN_TO_HOST_INT32(video_format->compression); 350 351 cookie->audio = false; 352 cookie->line_count = theFileReader->MovMainHeader()->height; 353 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); 362 } else { 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); 366 } 367 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; 370 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)); 374 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; 378 else 379 description.u.quicktime.codec = video_format->compression; 380 if (B_OK != formats.GetFormatFor(description, format)) 381 format->type = B_MEDIA_ENCODED_VIDEO; 382 383 format->user_data_type = B_CODEC_TYPE_INFO; 384 *(uint32 *)format->user_data = description.u.quicktime.codec; format->user_data[4] = 0; 385 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; 401 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); 404 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; 408 if (size > 0) { 409 TRACE("VOL SIZE %ld\n", size); 410 format->SetMetaData(data, size); 411 } 412 413 if (codecID != 0) { 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; 417 } 418 419 return B_OK; 420 } 421 422 delete cookie; 423 return B_ERROR; 424} 425 426 427status_t 428movReader::FreeCookie(void *_cookie) 429{ 430 mov_cookie *cookie = (mov_cookie *)_cookie; 431 432 delete [] cookie->buffer; 433 434 delete cookie; 435 return B_OK; 436} 437 438 439status_t 440movReader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration, 441 media_format *format, const void **infoBuffer, size_t *infoSize) 442{ 443 mov_cookie *cookie = (mov_cookie *)_cookie; 444 445 if (cookie) { 446 *frameCount = cookie->frame_count; 447 *duration = cookie->duration; 448 *format = cookie->format; 449 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; 455 } else { 456 const AudioMetaData *audio_format = theFileReader->AudioFormat(cookie->stream); 457 *infoBuffer = audio_format->theVOL; 458 *infoSize = audio_format->VOLSize; 459 } 460 } 461 462 return B_OK; 463} 464 465 466status_t 467movReader::Seek(void *cookie, 468 uint32 seekTo, 469 int64 *frame, bigtime_t *time) 470{ 471 // Seek to the requested frame 472 473 mov_cookie *movcookie = (mov_cookie *)cookie; 474 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); 480 } 481 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); 487 } 488 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" : "", 494 *time, *frame); 495 496 return B_OK; 497} 498 499status_t 500movReader::FindKeyFrame(void* cookie, uint32 flags, 501 int64* frame, bigtime_t* time) 502{ 503 // Find the nearest keyframe to the given time or frame. 504 505 mov_cookie *movcookie = (mov_cookie *)cookie; 506 507 bool keyframe = false; 508 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; 513 } 514 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" : "", 520 *time, *frame); 521 522 if (movcookie->audio) { 523 // Audio does not have keyframes? Or all audio frames are keyframes? 524 return B_OK; 525 } else { 526 while (*frame > 0 && *frame <= movcookie->frame_count) { 527 keyframe = theFileReader->IsKeyFrame(movcookie->stream, *frame); 528 529 if (keyframe) 530 break; 531 532 if (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) { 533 (*frame)--; 534 } else { 535 (*frame)++; 536 } 537 } 538 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; 543 } 544 } 545 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; 549 550 TRACE("Found keyframe at frame %Ld time %Ld\n",*frame,*time); 551 552 return B_OK; 553} 554 555status_t 556movReader::GetNextChunk(void *_cookie, 557 const void **chunkBuffer, size_t *chunkSize, 558 media_header *mediaHeader) 559{ 560 mov_cookie *cookie = (mov_cookie *)_cookie; 561 562 int64 start; uint32 size; bool keyframe; uint32 chunkFrameCount; 563 564 if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe, &chunkFrameCount)) 565 return B_LAST_BUFFER_ERROR; 566 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]; 571 } 572 573 if (cookie->audio) { 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; 577 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); 581 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); 586 587 cookie->byte_pos += size; 588 } else { 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; 595 } 596 597 cookie->frame_pos += chunkFrameCount; 598 TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0); 599 600 *chunkBuffer = cookie->buffer; 601 *chunkSize = size; 602 return (int)size == theFileReader->Source()->ReadAt(start, cookie->buffer, size) ? B_OK : B_LAST_BUFFER_ERROR; 603} 604 605 606Reader * 607movReaderPlugin::NewReader() 608{ 609 return new movReader; 610} 611 612 613MediaPlugin *instantiate_plugin() 614{ 615 return new movReaderPlugin; 616} 617