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