xref: /haiku/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp (revision eb47b26534e55948dbb8860916c671f9cf6f37f9)
1 /*
2  * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
3  * All rights reserved. Distributed under the terms of the GNU L-GPL license.
4  */
5 
6 #include "AVFormatReader.h"
7 
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 
12 #include <new>
13 
14 #include <AutoDeleter.h>
15 #include <Autolock.h>
16 #include <ByteOrder.h>
17 #include <DataIO.h>
18 #include <MediaDefs.h>
19 #include <MediaFormats.h>
20 
21 extern "C" {
22 	#include "avformat.h"
23 }
24 
25 #include "DemuxerTable.h"
26 #include "gfx_util.h"
27 
28 
29 #define TRACE_AVFORMAT_READER
30 #ifdef TRACE_AVFORMAT_READER
31 #	define TRACE printf
32 #	define TRACE_IO(a...)
33 #	define TRACE_SEEK(a...)
34 #	define TRACE_PACKET(a...)
35 #else
36 #	define TRACE(a...)
37 #	define TRACE_IO(a...)
38 #	define TRACE_SEEK(a...)
39 #	define TRACE_PACKET(a...)
40 #endif
41 
42 #define ERROR(a...) fprintf(stderr, a)
43 
44 
45 static const size_t kIOBufferSize = 64 * 1024;
46 	// TODO: This could depend on the BMediaFile creation flags, IIRC,
47 	// they allow to specify a buffering mode.
48 
49 uint32
50 avformat_to_beos_format(SampleFormat format)
51 {
52 	switch (format) {
53 		case SAMPLE_FMT_U8: return media_raw_audio_format::B_AUDIO_UCHAR;
54 		case SAMPLE_FMT_S16: return media_raw_audio_format::B_AUDIO_SHORT;
55 		case SAMPLE_FMT_S32: return media_raw_audio_format::B_AUDIO_INT;
56 		case SAMPLE_FMT_FLT: return media_raw_audio_format::B_AUDIO_FLOAT;
57 		case SAMPLE_FMT_DBL: return media_raw_audio_format::B_AUDIO_DOUBLE;
58 		default:
59 			break;
60 	}
61 	return 0;
62 }
63 
64 
65 // #pragma mark - AVFormatReader::StreamCookie
66 
67 
68 class AVFormatReader::StreamCookie {
69 public:
70 								StreamCookie(BPositionIO* source,
71 									BLocker* streamLock);
72 	virtual						~StreamCookie();
73 
74 	// Init an indivual AVFormatContext
75 			status_t			Open();
76 
77 	// Setup this stream to point to the AVStream at the given streamIndex.
78 	// This will also initialize the media_format.
79 			status_t			Init(int32 streamIndex);
80 
81 	inline	const AVFormatContext* Context() const
82 									{ return fContext; }
83 			int32				Index() const;
84 			int32				CountStreams() const;
85 			int32				StreamIndexFor(int32 virtualIndex) const;
86 	inline	int32				VirtualIndex() const
87 									{ return fVirtualIndex; }
88 
89 	inline	const media_format&	Format() const
90 									{ return fFormat; }
91 
92 			double				FrameRate() const;
93 
94 	// Support for AVFormatReader
95 			status_t			GetStreamInfo(int64* frameCount,
96 									bigtime_t* duration, media_format* format,
97 									const void** infoBuffer,
98 									size_t* infoSize) const;
99 
100 			status_t			Seek(uint32 flags, int64* frame,
101 									bigtime_t* time);
102 			status_t			FindKeyFrame(uint32 flags, int64* frame,
103 									bigtime_t* time) const;
104 
105 			status_t			GetNextChunk(const void** chunkBuffer,
106 									size_t* chunkSize,
107 									media_header* mediaHeader);
108 
109 private:
110 	// I/O hooks for libavformat, cookie will be a StreamCookie instance.
111 	// Since multiple StreamCookies use the same BPositionIO source, they
112 	// maintain the position individually, and may need to seek the source
113 	// if it does not match anymore in _Read().
114 	// TODO: This concept prevents the use of a plain BDataIO that is not
115 	// seekable. There is a version of AVFormatReader in the SVN history
116 	// which implements packet buffering for other streams when reading
117 	// packets. To support non-seekable network streams for example, this
118 	// code should be resurrected. It will make handling seekable streams,
119 	// especially from different threads that read from totally independent
120 	// positions in the stream (aggressive pre-buffering perhaps), a lot
121 	// more difficult with potentially large memory overhead.
122 	static	int					_Read(void* cookie, uint8* buffer,
123 									int bufferSize);
124 	static	off_t				_Seek(void* cookie, off_t offset, int whence);
125 
126 			status_t			_NextPacket(bool reuse);
127 
128 private:
129 			BPositionIO*		fSource;
130 			off_t				fPosition;
131 			// Since different threads may read from the source,
132 			// we need to protect the file position and I/O by a lock.
133 			BLocker*			fStreamLock;
134 
135 			AVFormatContext*	fContext;
136 			AVStream*			fStream;
137 			int32				fVirtualIndex;
138 
139 			ByteIOContext		fIOContext;
140 			uint8				fIOBuffer[kIOBufferSize];
141 
142 			AVPacket			fPacket;
143 			bool				fReusePacket;
144 
145 			media_format		fFormat;
146 };
147 
148 
149 
150 AVFormatReader::StreamCookie::StreamCookie(BPositionIO* source,
151 		BLocker* streamLock)
152 	:
153 	fSource(source),
154 	fPosition(0),
155 	fStreamLock(streamLock),
156 
157 	fContext(NULL),
158 	fStream(NULL),
159 	fVirtualIndex(-1),
160 
161 	fReusePacket(false)
162 {
163 	memset(&fIOBuffer, 0, sizeof(fIOBuffer));
164 	memset(&fFormat, 0, sizeof(media_format));
165 	av_new_packet(&fPacket, 0);
166 }
167 
168 
169 AVFormatReader::StreamCookie::~StreamCookie()
170 {
171 	av_free_packet(&fPacket);
172 	av_free(fContext);
173 }
174 
175 
176 status_t
177 AVFormatReader::StreamCookie::Open()
178 {
179 	// Init probing data
180 	size_t probeSize = 2048;
181 	AVProbeData probeData;
182 	probeData.filename = "";
183 	probeData.buf = fIOBuffer;
184 	probeData.buf_size = probeSize;
185 
186 	// Read a bit of the input...
187 	// NOTE: Even if other streams have already read from the source,
188 	// it is ok to not seek first, since our fPosition is 0, so the necessary
189 	// seek will happen automatically in _Read().
190 	if (_Read(this, fIOBuffer, probeSize) != (ssize_t)probeSize)
191 		return B_IO_ERROR;
192 	// ...and seek back to the beginning of the file. This is important
193 	// since libavformat will assume the stream to be at offset 0, the
194 	// probe data is not reused.
195 	_Seek(this, 0, SEEK_SET);
196 
197 	// Probe the input format
198 	AVInputFormat* inputFormat = av_probe_input_format(&probeData, 1);
199 
200 	if (inputFormat == NULL) {
201 		TRACE("AVFormatReader::StreamCookie::Open() - "
202 			"av_probe_input_format() failed!\n");
203 		return B_NOT_SUPPORTED;
204 	}
205 
206 	TRACE("AVFormatReader::StreamCookie::Open() - "
207 		"av_probe_input_format(): %s\n", inputFormat->name);
208 
209 	const DemuxerFormat* demuxerFormat = demuxer_format_for(inputFormat);
210 	if (demuxerFormat == NULL) {
211 		// We could support this format, but we don't want to. Bail out.
212 		ERROR("AVFormatReader::StreamCookie::Open() - "
213 			"support for demuxer '%s' is not enabled. "
214 			"See DemuxerTable.cpp\n", inputFormat->name);
215 		return B_NOT_SUPPORTED;
216 	}
217 
218 	// Init I/O context with buffer and hook functions, pass ourself as
219 	// cookie.
220 	if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, this,
221 			_Read, 0, _Seek) != 0) {
222 		TRACE("AVFormatReader::StreamCookie::Open() - "
223 			"init_put_byte() failed!\n");
224 		return B_ERROR;
225 	}
226 
227 	// Initialize our context.
228 	if (av_open_input_stream(&fContext, &fIOContext, "", inputFormat,
229 			NULL) < 0) {
230 		TRACE("AVFormatReader::StreamCookie::Open() - "
231 			"av_open_input_stream() failed!\n");
232 		return B_NOT_SUPPORTED;
233 	}
234 
235 	// Retrieve stream information
236 	if (av_find_stream_info(fContext) < 0) {
237 		TRACE("AVFormatReader::StreamCookie::Open() - "
238 			"av_find_stream_info() failed!\n");
239 		return B_NOT_SUPPORTED;
240 	}
241 
242 	TRACE("AVFormatReader::StreamCookie::Open() - "
243 		"av_find_stream_info() success!\n");
244 
245 	return B_OK;
246 }
247 
248 
249 status_t
250 AVFormatReader::StreamCookie::Init(int32 virtualIndex)
251 {
252 	TRACE("AVFormatReader::StreamCookie::Init(%ld)\n", virtualIndex);
253 
254 	if (fContext == NULL)
255 		return B_NO_INIT;
256 
257 	int32 streamIndex = StreamIndexFor(virtualIndex);
258 	if (streamIndex < 0) {
259 		TRACE("  Bad stream index!\n");
260 		return B_BAD_INDEX;
261 	}
262 
263 	TRACE("  context stream index: %ld\n", streamIndex);
264 
265 	const DemuxerFormat* demuxerFormat = demuxer_format_for(fContext->iformat);
266 	if (demuxerFormat == NULL) {
267 		TRACE("  unknown AVInputFormat!\n");
268 		return B_NOT_SUPPORTED;
269 	}
270 
271 	// We need to remember the virtual index so that
272 	// AVFormatReader::FreeCookie() can clear the correct stream entry.
273 	fVirtualIndex = virtualIndex;
274 
275 	// Make us point to the AVStream at streamIndex
276 	fStream = fContext->streams[streamIndex];
277 
278 	// Discard all other streams
279 	for (unsigned i = 0; i < fContext->nb_streams; i++) {
280 		if (i != (unsigned)streamIndex)
281 			fContext->streams[i]->discard = AVDISCARD_ALL;
282 	}
283 
284 	// Get a pointer to the AVCodecContext for the stream at streamIndex.
285 	AVCodecContext* codecContext = fStream->codec;
286 	AVStream* stream = fStream;
287 
288 	// initialize the media_format for this stream
289 	media_format* format = &fFormat;
290 	memset(format, 0, sizeof(media_format));
291 
292 	media_format_description description;
293 
294 	// Set format family and type depending on codec_type of the stream.
295 	switch (codecContext->codec_type) {
296 		case CODEC_TYPE_AUDIO:
297 			if ((codecContext->codec_id >= CODEC_ID_PCM_S16LE)
298 				&& (codecContext->codec_id <= CODEC_ID_PCM_U8)) {
299 				TRACE("  raw audio\n");
300 				format->type = B_MEDIA_RAW_AUDIO;
301 				description.family = B_ANY_FORMAT_FAMILY;
302 			} else {
303 				TRACE("  encoded audio\n");
304 				format->type = B_MEDIA_ENCODED_AUDIO;
305 				description.family = demuxerFormat->audio_family;
306 			}
307 			break;
308 		case CODEC_TYPE_VIDEO:
309 			TRACE("  encoded video\n");
310 			format->type = B_MEDIA_ENCODED_VIDEO;
311 			description.family = demuxerFormat->video_family;
312 			break;
313 		default:
314 			TRACE("  unknown type\n");
315 			format->type = B_MEDIA_UNKNOWN_TYPE;
316 			break;
317 	}
318 
319 	if (format->type == B_MEDIA_RAW_AUDIO) {
320 		switch (codecContext->codec_id) {
321 			case CODEC_ID_PCM_S16LE:
322 				format->u.raw_audio.format
323 					= media_raw_audio_format::B_AUDIO_SHORT;
324 				format->u.raw_audio.byte_order
325 					= B_MEDIA_LITTLE_ENDIAN;
326 				break;
327 			case CODEC_ID_PCM_S16BE:
328 				format->u.raw_audio.format
329 					= media_raw_audio_format::B_AUDIO_SHORT;
330 				format->u.raw_audio.byte_order
331 					= B_MEDIA_BIG_ENDIAN;
332 				break;
333 			case CODEC_ID_PCM_U16LE:
334 //				format->u.raw_audio.format
335 //					= media_raw_audio_format::B_AUDIO_USHORT;
336 //				format->u.raw_audio.byte_order
337 //					= B_MEDIA_LITTLE_ENDIAN;
338 				return B_NOT_SUPPORTED;
339 				break;
340 			case CODEC_ID_PCM_U16BE:
341 //				format->u.raw_audio.format
342 //					= media_raw_audio_format::B_AUDIO_USHORT;
343 //				format->u.raw_audio.byte_order
344 //					= B_MEDIA_BIG_ENDIAN;
345 				return B_NOT_SUPPORTED;
346 				break;
347 			case CODEC_ID_PCM_S8:
348 				format->u.raw_audio.format
349 					= media_raw_audio_format::B_AUDIO_CHAR;
350 				break;
351 			case CODEC_ID_PCM_U8:
352 				format->u.raw_audio.format
353 					= media_raw_audio_format::B_AUDIO_UCHAR;
354 				break;
355 			default:
356 				return B_NOT_SUPPORTED;
357 				break;
358 		}
359 	} else {
360 		uint32 codecTag = codecContext->codec_tag;
361 		if (codecTag == 0) {
362 			// Ugh, no codec_tag. Let's try to fake some known codecs.
363 			// Such a situation seems to occur for the "mpegts" demuxer for
364 			// example. These are some tags I could test with.
365 			switch (codecContext->codec_id) {
366 				case CODEC_ID_H264:
367 					codecTag = 'h264';
368 					break;
369 				case CODEC_ID_DVVIDEO:
370 					codecTag = 'pcvd';
371 					break;
372 				case CODEC_ID_AC3:
373 					description.family = B_WAV_FORMAT_FAMILY;
374 					codecTag = 0x2000;
375 					break;
376 				case CODEC_ID_FLAC:
377 					description.family = B_WAV_FORMAT_FAMILY;
378 					codecTag = 'flac';
379 					break;
380 				case CODEC_ID_VP6F:
381 					description.family = B_QUICKTIME_FORMAT_FAMILY;
382 					codecTag = B_BENDIAN_TO_HOST_INT32('VP6F');
383 					break;
384 				case CODEC_ID_MP3:
385 					description.family = B_QUICKTIME_FORMAT_FAMILY;
386 					codecTag = B_BENDIAN_TO_HOST_INT32('.mp3');
387 					break;
388 				default:
389 					fprintf(stderr, "ffmpeg codecTag is null, codec_id "
390 						"unknown 0x%x\n", codecContext->codec_id);
391 					// TODO: Add more...
392 					break;
393 			}
394 		}
395 		switch (description.family) {
396 			case B_AIFF_FORMAT_FAMILY:
397 				TRACE("  B_AIFF_FORMAT_FAMILY\n");
398 				description.u.aiff.codec = codecTag;
399 				break;
400 			case B_ASF_FORMAT_FAMILY:
401 				TRACE("  B_ASF_FORMAT_FAMILY\n");
402 //				description.u.asf.guid = GUID(codecTag);
403 				return B_NOT_SUPPORTED;
404 				break;
405 			case B_AVI_FORMAT_FAMILY:
406 				TRACE("  B_AVI_FORMAT_FAMILY\n");
407 				description.u.avi.codec = codecTag;
408 				break;
409 			case B_AVR_FORMAT_FAMILY:
410 				TRACE("  B_AVR_FORMAT_FAMILY\n");
411 				description.u.avr.id = codecTag;
412 				break;
413 			case B_MPEG_FORMAT_FAMILY:
414 				TRACE("  B_MPEG_FORMAT_FAMILY\n");
415 				if (codecContext->codec_id == CODEC_ID_MPEG1VIDEO)
416 					description.u.mpeg.id = B_MPEG_1_VIDEO;
417 				else if (codecContext->codec_id == CODEC_ID_MPEG2VIDEO)
418 					description.u.mpeg.id = B_MPEG_2_VIDEO;
419 				else if (codecContext->codec_id == CODEC_ID_MP2)
420 					description.u.mpeg.id = B_MPEG_2_AUDIO_LAYER_2;
421 				else if (codecContext->codec_id == CODEC_ID_MP3)
422 					description.u.mpeg.id = B_MPEG_1_AUDIO_LAYER_3;
423 				// TODO: Add some more...
424 				else
425 					description.u.mpeg.id = B_MPEG_ANY;
426 				break;
427 			case B_QUICKTIME_FORMAT_FAMILY:
428 				TRACE("  B_QUICKTIME_FORMAT_FAMILY\n");
429 				description.u.quicktime.codec
430 					= B_HOST_TO_BENDIAN_INT32(codecTag);
431 				break;
432 			case B_WAV_FORMAT_FAMILY:
433 				TRACE("  B_WAV_FORMAT_FAMILY\n");
434 				description.u.wav.codec = codecTag;
435 				break;
436 			case B_MISC_FORMAT_FAMILY:
437 				TRACE("  B_MISC_FORMAT_FAMILY\n");
438 				description.u.misc.codec = codecTag;
439 				break;
440 
441 			default:
442 				break;
443 		}
444 		TRACE("  codecTag '%.4s' or %ld\n", (char*)&codecTag, codecTag);
445 		TRACE("  fourcc '%.4s'\n", (char*)&codecContext->codec_id);
446 
447 		BMediaFormats formats;
448 		status_t status = formats.GetFormatFor(description, format);
449 		if (status < B_OK)
450 			TRACE("  formats.GetFormatFor() error: %s\n", strerror(status));
451 
452 		format->user_data_type = B_CODEC_TYPE_INFO;
453 		*(uint32*)format->user_data = codecTag;
454 		format->user_data[4] = 0;
455 	}
456 
457 //	format->require_flags = 0;
458 	format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
459 
460 	switch (format->type) {
461 		case B_MEDIA_RAW_AUDIO:
462 			format->u.raw_audio.frame_rate = (float)codecContext->sample_rate;
463 			format->u.raw_audio.channel_count = codecContext->channels;
464 			format->u.encoded_audio.output.format
465 				= avformat_to_beos_format(codecContext->sample_fmt);
466 			format->u.raw_audio.buffer_size = 0;
467 
468 			// Read one packet and mark it for later re-use. (So our first
469 			// GetNextChunk() call does not read another packet.)
470 			if (_NextPacket(true) == B_OK) {
471 				TRACE("  successfully determined audio buffer size: %d\n",
472 					fPacket.size);
473 				format->u.raw_audio.buffer_size = fPacket.size;
474 			}
475 			break;
476 
477 		case B_MEDIA_ENCODED_AUDIO:
478 			format->u.encoded_audio.bit_rate = codecContext->bit_rate;
479 			format->u.encoded_audio.frame_size = codecContext->frame_size;
480 			// Fill in some info about possible output format
481 			format->u.encoded_audio.output
482 				= media_multi_audio_format::wildcard;
483 			format->u.encoded_audio.output.frame_rate
484 				= (float)codecContext->sample_rate;
485 			format->u.encoded_audio.output.channel_count
486 				= codecContext->channels;
487 			format->u.encoded_audio.output.format
488 				= avformat_to_beos_format(codecContext->sample_fmt);
489 			break;
490 
491 		case B_MEDIA_ENCODED_VIDEO:
492 // TODO: Specifying any of these seems to throw off the format matching
493 // later on.
494 //			format->u.encoded_video.avg_bit_rate = codecContext->bit_rate;
495 //			format->u.encoded_video.max_bit_rate = codecContext->bit_rate
496 //				+ codecContext->bit_rate_tolerance;
497 
498 //			format->u.encoded_video.encoding
499 //				= media_encoded_video_format::B_ANY;
500 
501 //			format->u.encoded_video.frame_size = 1;
502 //			format->u.encoded_video.forward_history = 0;
503 //			format->u.encoded_video.backward_history = 0;
504 
505 			// TODO: Fix up for interlaced video
506 			format->u.encoded_video.output.field_rate
507 				= av_q2d(stream->r_frame_rate);
508 if (format->u.encoded_video.output.field_rate == 50.0f)
509 	format->u.encoded_video.output.field_rate = 25.0f;
510 			format->u.encoded_video.output.interlace = 1;
511 
512 			format->u.encoded_video.output.first_active = 0;
513 			format->u.encoded_video.output.last_active
514 				= codecContext->height - 1;
515 				// TODO: Maybe libavformat actually provides that info
516 				// somewhere...
517 			format->u.encoded_video.output.orientation
518 				= B_VIDEO_TOP_LEFT_RIGHT;
519 
520 			// Calculate the display aspect ratio
521 			AVRational displayAspectRatio;
522 		    if (codecContext->sample_aspect_ratio.num != 0) {
523 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
524 					codecContext->width
525 						* codecContext->sample_aspect_ratio.num,
526 					codecContext->height
527 						* codecContext->sample_aspect_ratio.den,
528 					1024 * 1024);
529 				TRACE("  pixel aspect ratio: %d/%d, "
530 					"display aspect ratio: %d/%d\n",
531 					codecContext->sample_aspect_ratio.num,
532 					codecContext->sample_aspect_ratio.den,
533 					displayAspectRatio.num, displayAspectRatio.den);
534 		    } else {
535 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
536 					codecContext->width, codecContext->height, 1024 * 1024);
537 				TRACE("  no display aspect ratio (%d/%d)\n",
538 					displayAspectRatio.num, displayAspectRatio.den);
539 		    }
540 			format->u.encoded_video.output.pixel_width_aspect
541 				= displayAspectRatio.num;
542 			format->u.encoded_video.output.pixel_height_aspect
543 				= displayAspectRatio.den;
544 
545 			format->u.encoded_video.output.display.format
546 				= pixfmt_to_colorspace(codecContext->pix_fmt);
547 			format->u.encoded_video.output.display.line_width
548 				= codecContext->width;
549 			format->u.encoded_video.output.display.line_count
550 				= codecContext->height;
551 			format->u.encoded_video.output.display.bytes_per_row = 0;
552 			format->u.encoded_video.output.display.pixel_offset = 0;
553 			format->u.encoded_video.output.display.line_offset = 0;
554 			format->u.encoded_video.output.display.flags = 0; // TODO
555 
556 			break;
557 
558 		default:
559 			// This is an unknown format to us.
560 			break;
561 	}
562 
563 	// Add the meta data, if any
564 	if (codecContext->extradata_size > 0) {
565 		format->SetMetaData(codecContext->extradata,
566 			codecContext->extradata_size);
567 		TRACE("  extradata: %p\n", format->MetaData());
568 	}
569 
570 	TRACE("  extradata_size: %d\n", codecContext->extradata_size);
571 	TRACE("  intra_matrix: %p\n", codecContext->intra_matrix);
572 	TRACE("  inter_matrix: %p\n", codecContext->inter_matrix);
573 	TRACE("  get_buffer(): %p\n", codecContext->get_buffer);
574 	TRACE("  release_buffer(): %p\n", codecContext->release_buffer);
575 
576 #ifdef TRACE_AVFORMAT_READER
577 	char formatString[512];
578 	if (string_for_format(*format, formatString, sizeof(formatString)))
579 		TRACE("  format: %s\n", formatString);
580 
581 	uint32 encoding = format->Encoding();
582 	TRACE("  encoding '%.4s'\n", (char*)&encoding);
583 #endif
584 
585 	return B_OK;
586 }
587 
588 
589 int32
590 AVFormatReader::StreamCookie::Index() const
591 {
592 	if (fStream != NULL)
593 		return fStream->index;
594 	return -1;
595 }
596 
597 
598 int32
599 AVFormatReader::StreamCookie::CountStreams() const
600 {
601 	// Figure out the stream count. If the context has "AVPrograms", use
602 	// the first program (for now).
603 	// TODO: To support "programs" properly, the BMediaFile/Track API should
604 	// be extended accordingly. I guess programs are like TV channels in the
605 	// same satilite transport stream. Maybe call them "TrackGroups".
606 	if (fContext->nb_programs > 0) {
607 		// See libavformat/utils.c:dump_format()
608 		return fContext->programs[0]->nb_stream_indexes;
609 	}
610 	return fContext->nb_streams;
611 }
612 
613 
614 int32
615 AVFormatReader::StreamCookie::StreamIndexFor(int32 virtualIndex) const
616 {
617 	// NOTE: See CountStreams()
618 	if (fContext->nb_programs > 0) {
619 		const AVProgram* program = fContext->programs[0];
620 		if (virtualIndex >= 0
621 			&& virtualIndex < (int32)program->nb_stream_indexes) {
622 			return program->stream_index[virtualIndex];
623 		}
624 	} else {
625 		if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams)
626 			return virtualIndex;
627 	}
628 	return -1;
629 }
630 
631 
632 double
633 AVFormatReader::StreamCookie::FrameRate() const
634 {
635 	// TODO: Find a way to always calculate a correct frame rate...
636 	double frameRate;
637 	switch (fStream->codec->codec_type) {
638 		case CODEC_TYPE_AUDIO:
639 			frameRate = (double)fStream->codec->sample_rate;
640 			break;
641 		case CODEC_TYPE_VIDEO:
642 			frameRate = av_q2d(fStream->r_frame_rate);
643 			break;
644 		default:
645 			frameRate = 1.0;
646 			break;
647 	}
648 	if (frameRate <= 0.0)
649 		frameRate = 1.0;
650 	return frameRate;
651 }
652 
653 
654 status_t
655 AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount,
656 	bigtime_t* duration, media_format* format, const void** infoBuffer,
657 	size_t* infoSize) const
658 {
659 	TRACE("AVFormatReader::StreamCookie::GetStreamInfo(%ld)\n",
660 		VirtualIndex());
661 
662 	double frameRate = FrameRate();
663 	TRACE("  frameRate: %.4f\n", frameRate);
664 
665 	// TODO: This is obviously not working correctly for all stream types...
666 	// It seems that the calculations here are correct, because they work
667 	// for a couple of streams and are in line with the documentation, but
668 	// unfortunately, libavformat itself seems to set the time_base and
669 	// duration wrongly sometimes. :-(
670 	static const int64 kNoPTSValue = 0x8000000000000000LL;
671 		// NOTE: For some reasons, I have trouble with the avcodec.h define:
672 		// #define AV_NOPTS_VALUE          INT64_C(0x8000000000000000)
673 		// INT64_C is not defined here.
674 	if ((int64)fStream->duration != kNoPTSValue) {
675 		*duration = (bigtime_t)(1000000LL * fStream->duration
676 			* fStream->time_base.num / fStream->time_base.den);
677 		TRACE("  stream duration: %lld, time_base %.4f (%d/%d)\n",
678 			fStream->duration, av_q2d(fStream->time_base),
679 			fStream->time_base.num, fStream->time_base.den);
680 	} else if ((int64)fContext->duration != kNoPTSValue) {
681 		*duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE);
682 		TRACE("  stream duration: %lld (from AVFormatContext)\n",
683 			*duration);
684 	} else {
685 		*duration = 0;
686 		TRACE("  stream duration: N/A\n");
687 	}
688 
689 	TRACE("  duration: %lld or %.2fs\n", *duration, *duration / 1000000.0);
690 
691 	*frameCount = fStream->nb_frames;
692 	if (*frameCount == 0) {
693 		// Calculate from duration and frame rate
694 		*frameCount = (int64)(*duration * frameRate / 1000000LL);
695 		TRACE("  frameCount (calculated): %lld\n", *frameCount);
696 	} else
697 		TRACE("  frameCount: %lld\n", *frameCount);
698 
699 	*format = fFormat;
700 
701 	// TODO: Possibly use fStream->metadata for this?
702 	*infoBuffer = 0;
703 	*infoSize = 0;
704 
705 	return B_OK;
706 }
707 
708 
709 status_t
710 AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame,
711 	bigtime_t* time)
712 {
713 	if (fContext == NULL || fStream == NULL)
714 		return B_NO_INIT;
715 
716 	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) {
717 		TRACE_SEEK("AVFormatReader::StreamCookie::Seek() - "
718 			"B_MEDIA_SEEK_CLOSEST_FORWARD not supported.\n");
719 		return B_NOT_SUPPORTED;
720 	}
721 
722 	TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, "
723 		"%lld)\n", VirtualIndex(),
724 		(flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
725 		(flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
726 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
727 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
728 		*frame, *time);
729 
730 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
731 		*time = (bigtime_t)(*frame * 1000000LL / FrameRate());
732 
733 	double timeBase = av_q2d(fStream->time_base);
734 	int64_t timeStamp;
735 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
736 		// Can use frame, because stream timeStamp is actually in frame
737 		// units.
738 		timeStamp = *frame;
739 	} else
740 		timeStamp = (int64_t)(*time / timeBase / 1000000.0);
741 
742 	TRACE_SEEK("  time: %.2fs -> %lld, current DTS: %lld (time_base: %f)\n",
743 		*time / 1000000.0, timeStamp, fStream->cur_dts, timeBase);
744 
745 	if (av_seek_frame(fContext, Index(), timeStamp, 0) < 0) {
746 		TRACE_SEEK("  av_seek_frame() failed.\n");
747 		return B_ERROR;
748 	}
749 
750 	// Our last packet is toast in any case.
751 	av_free_packet(&fPacket);
752 	fReusePacket = false;
753 
754 	return B_OK;
755 }
756 
757 
758 status_t
759 AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame,
760 	bigtime_t* time) const
761 {
762 	if (fContext == NULL || fStream == NULL)
763 		return B_NO_INIT;
764 
765 	TRACE_SEEK("AVFormatReader::StreamCookie::FindKeyFrame(%ld, %s %s %s %s, "
766 		"%lld, %lld)\n", VirtualIndex(),
767 		(flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
768 		(flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
769 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
770 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
771 		*frame, *time);
772 
773 	double frameRate = FrameRate();
774 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
775 		*time = (bigtime_t)(*frame * 1000000LL / frameRate);
776 
777 	double timeBase = av_q2d(fStream->time_base);
778 	int64_t timeStamp;
779 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
780 		// Can use frame, because stream timeStamp is actually in frame
781 		// units.
782 		timeStamp = *frame;
783 	} else
784 		timeStamp = (int64_t)(*time / timeBase / 1000000.0);
785 
786 	TRACE_SEEK("  time: %.2fs -> %lld (time_base: %f)\n", *time / 1000000.0,
787 		timeStamp, timeBase);
788 
789 	int searchFlags = AVSEEK_FLAG_BACKWARD;
790 	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
791 		searchFlags = 0;
792 
793 	int index = av_index_search_timestamp(fStream, timeStamp, searchFlags);
794 	if (index < 0) {
795 		TRACE_SEEK("  av_index_search_timestamp() failed.\n");
796 		// Just seek to the beginning of the stream and assume it is a
797 		// keyframe...
798 		*frame = 0;
799 		*time = 0;
800 		return B_OK;
801 	}
802 
803 	const AVIndexEntry& entry = fStream->index_entries[index];
804 	timeStamp = entry.timestamp;
805 	*time = (bigtime_t)(timeStamp * 1000000.0 * timeBase);
806 
807 	TRACE_SEEK("  seeked time: %.2fs (%lld)\n", *time / 1000000.0, timeStamp);
808 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
809 		*frame = timeStamp;//*time * frameRate / 1000000LL;
810 		TRACE_SEEK("  seeked frame: %lld\n", *frame);
811 	}
812 
813 	return B_OK;
814 }
815 
816 
817 status_t
818 AVFormatReader::StreamCookie::GetNextChunk(const void** chunkBuffer,
819 	size_t* chunkSize, media_header* mediaHeader)
820 {
821 	TRACE_PACKET("AVFormatReader::StreamCookie::GetNextChunk()\n");
822 
823 	status_t ret = _NextPacket(false);
824 	if (ret != B_OK) {
825 		*chunkBuffer = NULL;
826 		*chunkSize = 0;
827 		return ret;
828 	}
829 
830 	// NOTE: AVPacket has a field called "convergence_duration", for which
831 	// the documentation is quite interesting. It sounds like it could be
832 	// used to know the time until the next I-Frame in streams that don't
833 	// let you know the position of keyframes in another way (like through
834 	// the index).
835 
836 	// According to libavformat documentation, fPacket is valid until the
837 	// next call to av_read_frame(). This is what we want and we can share
838 	// the memory with the least overhead.
839 	*chunkBuffer = fPacket.data;
840 	*chunkSize = fPacket.size;
841 
842 	if (mediaHeader != NULL) {
843 		mediaHeader->type = fFormat.type;
844 		mediaHeader->buffer = 0;
845 		mediaHeader->destination = -1;
846 		mediaHeader->time_source = -1;
847 		mediaHeader->size_used = fPacket.size;
848 //TRACE("  PTS: %lld (time_base.num: %d, .den: %d)\n",
849 //fPacket.pts, fStream->time_base.num, fStream->time_base.den);
850 		mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts
851 			/ av_q2d(fStream->time_base));
852 		mediaHeader->file_pos = fPacket.pos;
853 		mediaHeader->data_offset = 0;
854 		switch (mediaHeader->type) {
855 			case B_MEDIA_RAW_AUDIO:
856 				break;
857 			case B_MEDIA_ENCODED_AUDIO:
858 				mediaHeader->u.encoded_audio.buffer_flags
859 					= (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
860 				break;
861 			case B_MEDIA_RAW_VIDEO:
862 				mediaHeader->u.raw_video.line_count
863 					= fFormat.u.raw_video.display.line_count;
864 				break;
865 			case B_MEDIA_ENCODED_VIDEO:
866 				mediaHeader->u.encoded_video.field_flags
867 					= (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
868 				mediaHeader->u.encoded_video.line_count
869 					= fFormat.u.encoded_video.output.display.line_count;
870 				break;
871 			default:
872 				break;
873 		}
874 	}
875 
876 	return B_OK;
877 }
878 
879 
880 // #pragma mark -
881 
882 
883 /*static*/ int
884 AVFormatReader::StreamCookie::_Read(void* cookie, uint8* buffer,
885 	int bufferSize)
886 {
887 	TRACE_IO("AVFormatReader::StreamCookie::_Read(%p, %p, %d)\n",
888 		cookie, buffer, bufferSize);
889 
890 	StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie);
891 
892 	BAutolock _(stream->fStreamLock);
893 
894 	if (stream->fPosition != stream->fSource->Position()) {
895 		off_t position
896 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
897 		if (position != stream->fPosition)
898 			return -1;
899 	}
900 
901 	ssize_t read = stream->fSource->Read(buffer, bufferSize);
902 	if (read > 0)
903 		stream->fPosition += read;
904 
905 	TRACE_IO("  read: %ld\n", read);
906 	return (int)read;
907 
908 }
909 
910 
911 /*static*/ off_t
912 AVFormatReader::StreamCookie::_Seek(void* cookie, off_t offset, int whence)
913 {
914 	TRACE_IO("AVFormatReader::StreamCookie::_Seek(%p, %lld, %d)\n",
915 		cookie, offset, whence);
916 
917 	StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie);
918 
919 	BAutolock _(stream->fStreamLock);
920 
921 	// Support for special file size retrieval API without seeking
922 	// anywhere:
923 	if (whence == AVSEEK_SIZE) {
924 		off_t size;
925 		if (stream->fSource->GetSize(&size) == B_OK)
926 			return size;
927 		return -1;
928 	}
929 
930 	// If not requested to seek to an absolute position, we need to
931 	// confirm that the stream is currently at the position that we
932 	// think it is.
933 	if (whence != SEEK_SET
934 		&& stream->fPosition != stream->fSource->Position()) {
935 		off_t position
936 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
937 		if (position != stream->fPosition)
938 			return -1;
939 	}
940 
941 	off_t position = stream->fSource->Seek(offset, whence);
942 	TRACE_IO("  position: %lld\n", position);
943 	if (position < 0)
944 		return -1;
945 
946 	stream->fPosition = position;
947 
948 	return position;
949 }
950 
951 
952 status_t
953 AVFormatReader::StreamCookie::_NextPacket(bool reuse)
954 {
955 	TRACE_PACKET("AVFormatReader::StreamCookie::_NextPacket(%d)\n", reuse);
956 
957 	if (fReusePacket) {
958 		// The last packet was marked for reuse, so we keep using it.
959 		TRACE_PACKET("  re-using last packet\n");
960 		fReusePacket = reuse;
961 		return B_OK;
962 	}
963 
964 	av_free_packet(&fPacket);
965 
966 	while (true) {
967 		if (av_read_frame(fContext, &fPacket) < 0) {
968 			fReusePacket = false;
969 			return B_LAST_BUFFER_ERROR;
970 		}
971 
972 		if (fPacket.stream_index == Index())
973 			break;
974 
975 		// This is a packet from another stream, ignore it.
976 		av_free_packet(&fPacket);
977 	}
978 
979 	// Mark this packet with the new reuse flag.
980 	fReusePacket = reuse;
981 	return B_OK;
982 }
983 
984 
985 // #pragma mark - AVFormatReader
986 
987 
988 AVFormatReader::AVFormatReader()
989 	:
990 	fStreams(NULL),
991 	fStreamLock("stream lock")
992 {
993 	TRACE("AVFormatReader::AVFormatReader\n");
994 }
995 
996 
997 AVFormatReader::~AVFormatReader()
998 {
999 	TRACE("AVFormatReader::~AVFormatReader\n");
1000 	if (fStreams != NULL) {
1001 		delete fStreams[0];
1002 		delete[] fStreams;
1003 	}
1004 }
1005 
1006 
1007 // #pragma mark -
1008 
1009 
1010 const char*
1011 AVFormatReader::Copyright()
1012 {
1013 // TODO: Could not find the equivalent in libavformat >= version 53.
1014 //	if (fStreams != NULL && fStreams[0] != NULL)
1015 //		return fStreams[0]->Context()->copyright;
1016 	// TODO: Return copyright of the file instead!
1017 	return "Copyright 2009, Stephan Aßmus";
1018 }
1019 
1020 
1021 status_t
1022 AVFormatReader::Sniff(int32* _streamCount)
1023 {
1024 	TRACE("AVFormatReader::Sniff\n");
1025 
1026 	BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1027 	if (source == NULL) {
1028 		TRACE("  not a BPositionIO, but we need it to be one.\n");
1029 		return B_NOT_SUPPORTED;
1030 	}
1031 
1032 	StreamCookie* stream = new(std::nothrow) StreamCookie(source,
1033 		&fStreamLock);
1034 	if (stream == NULL) {
1035 		ERROR("AVFormatReader::Sniff() - failed to allocate StreamCookie\n");
1036 		return B_NO_MEMORY;
1037 	}
1038 
1039 	ObjectDeleter<StreamCookie> streamDeleter(stream);
1040 
1041 	status_t ret = stream->Open();
1042 	if (ret != B_OK) {
1043 		TRACE("  failed to detect stream: %s\n", strerror(ret));
1044 		return ret;
1045 	}
1046 
1047 	delete[] fStreams;
1048 	fStreams = NULL;
1049 
1050 	int32 streamCount = stream->CountStreams();
1051 	if (streamCount == 0) {
1052 		TRACE("  failed to detect any streams: %s\n", strerror(ret));
1053 		return B_ERROR;
1054 	}
1055 
1056 	fStreams = new(std::nothrow) StreamCookie*[streamCount];
1057 	if (fStreams == NULL) {
1058 		ERROR("AVFormatReader::Sniff() - failed to allocate streams\n");
1059 		return B_NO_MEMORY;
1060 	}
1061 
1062 	memset(fStreams, 0, sizeof(StreamCookie*) * streamCount);
1063 	fStreams[0] = stream;
1064 	streamDeleter.Detach();
1065 
1066 	#ifdef TRACE_AVFORMAT_READER
1067 	dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0);
1068 	#endif
1069 
1070 	if (_streamCount != NULL)
1071 		*_streamCount = streamCount;
1072 
1073 	return B_OK;
1074 }
1075 
1076 
1077 void
1078 AVFormatReader::GetFileFormatInfo(media_file_format* mff)
1079 {
1080 	TRACE("AVFormatReader::GetFileFormatInfo\n");
1081 
1082 	if (fStreams == NULL)
1083 		return;
1084 
1085 	// The first cookie is always there!
1086 	const AVFormatContext* context = fStreams[0]->Context();
1087 
1088 	if (context == NULL || context->iformat == NULL) {
1089 		TRACE("  no AVFormatContext or AVInputFormat!\n");
1090 		return;
1091 	}
1092 
1093 	const DemuxerFormat* format = demuxer_format_for(context->iformat);
1094 
1095 	mff->capabilities = media_file_format::B_READABLE
1096 		| media_file_format::B_KNOWS_ENCODED_VIDEO
1097 		| media_file_format::B_KNOWS_ENCODED_AUDIO
1098 		| media_file_format::B_IMPERFECTLY_SEEKABLE;
1099 
1100 	if (format != NULL) {
1101 		// TODO: Check if AVInputFormat has audio only and then use
1102 		// format->audio_family!
1103 		mff->family = format->video_family;
1104 	} else {
1105 		TRACE("  no DemuxerFormat for AVInputFormat!\n");
1106 		mff->family = B_MISC_FORMAT_FAMILY;
1107 	}
1108 
1109 	mff->version = 100;
1110 
1111 	if (format != NULL) {
1112 		strcpy(mff->mime_type, format->mime_type);
1113 	} else {
1114 		// TODO: Would be nice to be able to provide this from AVInputFormat,
1115 		// maybe by extending the FFmpeg code itself (all demuxers).
1116 		strcpy(mff->mime_type, "");
1117 	}
1118 
1119 	if (context->iformat->extensions != NULL)
1120 		strcpy(mff->file_extension, context->iformat->extensions);
1121 	else {
1122 		TRACE("  no file extensions for AVInputFormat.\n");
1123 		strcpy(mff->file_extension, "");
1124 	}
1125 
1126 	if (context->iformat->name != NULL)
1127 		strcpy(mff->short_name,  context->iformat->name);
1128 	else {
1129 		TRACE("  no short name for AVInputFormat.\n");
1130 		strcpy(mff->short_name, "");
1131 	}
1132 
1133 	if (context->iformat->long_name != NULL)
1134 		strcpy(mff->pretty_name, context->iformat->long_name);
1135 	else {
1136 		if (format != NULL)
1137 			strcpy(mff->pretty_name, format->pretty_name);
1138 		else
1139 			strcpy(mff->pretty_name, "");
1140 	}
1141 }
1142 
1143 
1144 // #pragma mark -
1145 
1146 
1147 status_t
1148 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie)
1149 {
1150 	TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex);
1151 
1152 	BAutolock _(fStreamLock);
1153 
1154 	if (fStreams == NULL)
1155 		return B_NO_INIT;
1156 
1157 	if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams())
1158 		return B_BAD_INDEX;
1159 
1160 	if (_cookie == NULL)
1161 		return B_BAD_VALUE;
1162 
1163 	StreamCookie* cookie = fStreams[streamIndex];
1164 	if (cookie == NULL) {
1165 		// Allocate the cookie
1166 		BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1167 		if (source == NULL) {
1168 			TRACE("  not a BPositionIO, but we need it to be one.\n");
1169 			return B_NOT_SUPPORTED;
1170 		}
1171 
1172 		cookie = new(std::nothrow) StreamCookie(source, &fStreamLock);
1173 		if (cookie == NULL) {
1174 			ERROR("AVFormatReader::Sniff() - failed to allocate "
1175 				"StreamCookie\n");
1176 			return B_NO_MEMORY;
1177 		}
1178 
1179 		status_t ret = cookie->Open();
1180 		if (ret != B_OK) {
1181 			TRACE("  stream failed to open: %s\n", strerror(ret));
1182 			delete cookie;
1183 			return ret;
1184 		}
1185 	}
1186 
1187 	status_t ret = cookie->Init(streamIndex);
1188 	if (ret != B_OK) {
1189 		TRACE("  stream failed to initialize: %s\n", strerror(ret));
1190 		// NOTE: Never delete the first stream!
1191 		if (streamIndex != 0)
1192 			delete cookie;
1193 		return ret;
1194 	}
1195 
1196 	fStreams[streamIndex] = cookie;
1197 	*_cookie = cookie;
1198 
1199 	return B_OK;
1200 }
1201 
1202 
1203 status_t
1204 AVFormatReader::FreeCookie(void *_cookie)
1205 {
1206 	BAutolock _(fStreamLock);
1207 
1208 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1209 
1210 	// NOTE: Never delete the first cookie!
1211 	if (cookie != NULL && cookie->VirtualIndex() != 0) {
1212 		if (fStreams != NULL)
1213 			fStreams[cookie->VirtualIndex()] = NULL;
1214 		delete cookie;
1215 	}
1216 
1217 	return B_OK;
1218 }
1219 
1220 
1221 // #pragma mark -
1222 
1223 
1224 status_t
1225 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
1226 	bigtime_t* duration, media_format* format, const void** infoBuffer,
1227 	size_t* infoSize)
1228 {
1229 	TRACE("AVFormatReader::GetStreamInfo()\n");
1230 
1231 //	BAutolock _(fStreamLock);
1232 
1233 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1234 	return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer,
1235 		infoSize);
1236 }
1237 
1238 
1239 status_t
1240 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame,
1241 	bigtime_t* time)
1242 {
1243 	TRACE_SEEK("AVFormatReader::Seek()\n");
1244 
1245 //	BAutolock _(fStreamLock);
1246 
1247 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1248 	return cookie->Seek(seekTo, frame, time);
1249 }
1250 
1251 
1252 status_t
1253 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame,
1254 	bigtime_t* time)
1255 {
1256 	TRACE_SEEK("AVFormatReader::FindKeyFrame()\n");
1257 
1258 //	BAutolock _(fStreamLock);
1259 
1260 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1261 	return cookie->FindKeyFrame(flags, frame, time);
1262 }
1263 
1264 
1265 status_t
1266 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer,
1267 	size_t* chunkSize, media_header* mediaHeader)
1268 {
1269 	TRACE_PACKET("AVFormatReader::GetNextChunk()\n");
1270 
1271 //	BAutolock _(fStreamLock);
1272 
1273 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1274 	return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
1275 }
1276 
1277 
1278