xref: /haiku/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp (revision 1345706a9ff6ad0dc041339a02d4259998b0765d)
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' or %d\n", (char*)&codecContext->codec_id,
484 			codecContext->codec_id);
485 
486 		BMediaFormats formats;
487 		status_t status = formats.GetFormatFor(description, format);
488 		if (status < B_OK)
489 			TRACE("  formats.GetFormatFor() error: %s\n", strerror(status));
490 
491 		format->user_data_type = B_CODEC_TYPE_INFO;
492 		*(uint32*)format->user_data = codecTag;
493 		format->user_data[4] = 0;
494 	}
495 
496 //	format->require_flags = 0;
497 	format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
498 
499 	switch (format->type) {
500 		case B_MEDIA_RAW_AUDIO:
501 			format->u.raw_audio.frame_rate = (float)codecContext->sample_rate;
502 			format->u.raw_audio.channel_count = codecContext->channels;
503 			format->u.raw_audio.byte_order
504 				= avformat_to_beos_byte_order(codecContext->sample_fmt);
505 			format->u.raw_audio.format
506 				= avformat_to_beos_format(codecContext->sample_fmt);
507 			format->u.raw_audio.buffer_size = 0;
508 
509 			// Read one packet and mark it for later re-use. (So our first
510 			// GetNextChunk() call does not read another packet.)
511 			if (_NextPacket(true) == B_OK) {
512 				TRACE("  successfully determined audio buffer size: %d\n",
513 					fPacket.size);
514 				format->u.raw_audio.buffer_size = fPacket.size;
515 			}
516 			break;
517 
518 		case B_MEDIA_ENCODED_AUDIO:
519 			format->u.encoded_audio.bit_rate = codecContext->bit_rate;
520 			format->u.encoded_audio.frame_size = codecContext->frame_size;
521 			// Fill in some info about possible output format
522 			format->u.encoded_audio.output
523 				= media_multi_audio_format::wildcard;
524 			format->u.encoded_audio.output.frame_rate
525 				= (float)codecContext->sample_rate;
526 			format->u.encoded_audio.output.channel_count
527 				= codecContext->channels;
528 			format->u.encoded_audio.output.byte_order
529 				= avformat_to_beos_byte_order(codecContext->sample_fmt);
530 			format->u.encoded_audio.output.format
531 				= avformat_to_beos_format(codecContext->sample_fmt);
532 			if (codecContext->block_align > 0) {
533 				format->u.encoded_audio.output.buffer_size
534 					= codecContext->block_align;
535 			} else {
536 				format->u.encoded_audio.output.buffer_size
537 					= codecContext->frame_size * codecContext->channels
538 						* (format->u.encoded_audio.output.format
539 							& media_raw_audio_format::B_AUDIO_SIZE_MASK);
540 			}
541 			break;
542 
543 		case B_MEDIA_ENCODED_VIDEO:
544 // TODO: Specifying any of these seems to throw off the format matching
545 // later on.
546 //			format->u.encoded_video.avg_bit_rate = codecContext->bit_rate;
547 //			format->u.encoded_video.max_bit_rate = codecContext->bit_rate
548 //				+ codecContext->bit_rate_tolerance;
549 
550 //			format->u.encoded_video.encoding
551 //				= media_encoded_video_format::B_ANY;
552 
553 //			format->u.encoded_video.frame_size = 1;
554 //			format->u.encoded_video.forward_history = 0;
555 //			format->u.encoded_video.backward_history = 0;
556 
557 			// TODO: Fix up for interlaced video
558 			format->u.encoded_video.output.field_rate
559 				= av_q2d(stream->r_frame_rate);
560 if (format->u.encoded_video.output.field_rate == 50.0f)
561 	format->u.encoded_video.output.field_rate = 25.0f;
562 			format->u.encoded_video.output.interlace = 1;
563 
564 			format->u.encoded_video.output.first_active = 0;
565 			format->u.encoded_video.output.last_active
566 				= codecContext->height - 1;
567 				// TODO: Maybe libavformat actually provides that info
568 				// somewhere...
569 			format->u.encoded_video.output.orientation
570 				= B_VIDEO_TOP_LEFT_RIGHT;
571 
572 			// Calculate the display aspect ratio
573 			AVRational displayAspectRatio;
574 		    if (codecContext->sample_aspect_ratio.num != 0) {
575 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
576 					codecContext->width
577 						* codecContext->sample_aspect_ratio.num,
578 					codecContext->height
579 						* codecContext->sample_aspect_ratio.den,
580 					1024 * 1024);
581 				TRACE("  pixel aspect ratio: %d/%d, "
582 					"display aspect ratio: %d/%d\n",
583 					codecContext->sample_aspect_ratio.num,
584 					codecContext->sample_aspect_ratio.den,
585 					displayAspectRatio.num, displayAspectRatio.den);
586 		    } else {
587 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
588 					codecContext->width, codecContext->height, 1024 * 1024);
589 				TRACE("  no display aspect ratio (%d/%d)\n",
590 					displayAspectRatio.num, displayAspectRatio.den);
591 		    }
592 			format->u.encoded_video.output.pixel_width_aspect
593 				= displayAspectRatio.num;
594 			format->u.encoded_video.output.pixel_height_aspect
595 				= displayAspectRatio.den;
596 
597 			format->u.encoded_video.output.display.format
598 				= pixfmt_to_colorspace(codecContext->pix_fmt);
599 			format->u.encoded_video.output.display.line_width
600 				= codecContext->width;
601 			format->u.encoded_video.output.display.line_count
602 				= codecContext->height;
603 			format->u.encoded_video.output.display.bytes_per_row = 0;
604 			format->u.encoded_video.output.display.pixel_offset = 0;
605 			format->u.encoded_video.output.display.line_offset = 0;
606 			format->u.encoded_video.output.display.flags = 0; // TODO
607 
608 			break;
609 
610 		default:
611 			// This is an unknown format to us.
612 			break;
613 	}
614 
615 	// Add the meta data, if any
616 	if (codecContext->extradata_size > 0) {
617 		format->SetMetaData(codecContext->extradata,
618 			codecContext->extradata_size);
619 		TRACE("  extradata: %p\n", format->MetaData());
620 	}
621 
622 	TRACE("  extradata_size: %d\n", codecContext->extradata_size);
623 	TRACE("  intra_matrix: %p\n", codecContext->intra_matrix);
624 	TRACE("  inter_matrix: %p\n", codecContext->inter_matrix);
625 	TRACE("  get_buffer(): %p\n", codecContext->get_buffer);
626 	TRACE("  release_buffer(): %p\n", codecContext->release_buffer);
627 
628 #ifdef TRACE_AVFORMAT_READER
629 	char formatString[512];
630 	if (string_for_format(*format, formatString, sizeof(formatString)))
631 		TRACE("  format: %s\n", formatString);
632 
633 	uint32 encoding = format->Encoding();
634 	TRACE("  encoding '%.4s'\n", (char*)&encoding);
635 #endif
636 
637 	return B_OK;
638 }
639 
640 
641 int32
642 AVFormatReader::StreamCookie::Index() const
643 {
644 	if (fStream != NULL)
645 		return fStream->index;
646 	return -1;
647 }
648 
649 
650 int32
651 AVFormatReader::StreamCookie::CountStreams() const
652 {
653 	// Figure out the stream count. If the context has "AVPrograms", use
654 	// the first program (for now).
655 	// TODO: To support "programs" properly, the BMediaFile/Track API should
656 	// be extended accordingly. I guess programs are like TV channels in the
657 	// same satilite transport stream. Maybe call them "TrackGroups".
658 	if (fContext->nb_programs > 0) {
659 		// See libavformat/utils.c:dump_format()
660 		return fContext->programs[0]->nb_stream_indexes;
661 	}
662 	return fContext->nb_streams;
663 }
664 
665 
666 int32
667 AVFormatReader::StreamCookie::StreamIndexFor(int32 virtualIndex) const
668 {
669 	// NOTE: See CountStreams()
670 	if (fContext->nb_programs > 0) {
671 		const AVProgram* program = fContext->programs[0];
672 		if (virtualIndex >= 0
673 			&& virtualIndex < (int32)program->nb_stream_indexes) {
674 			return program->stream_index[virtualIndex];
675 		}
676 	} else {
677 		if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams)
678 			return virtualIndex;
679 	}
680 	return -1;
681 }
682 
683 
684 double
685 AVFormatReader::StreamCookie::FrameRate() const
686 {
687 	// TODO: Find a way to always calculate a correct frame rate...
688 	double frameRate;
689 	switch (fStream->codec->codec_type) {
690 		case CODEC_TYPE_AUDIO:
691 			frameRate = (double)fStream->codec->sample_rate;
692 			break;
693 		case CODEC_TYPE_VIDEO:
694 			frameRate = av_q2d(fStream->r_frame_rate);
695 			break;
696 		default:
697 			frameRate = 1.0;
698 			break;
699 	}
700 	if (frameRate <= 0.0)
701 		frameRate = 1.0;
702 	return frameRate;
703 }
704 
705 
706 status_t
707 AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount,
708 	bigtime_t* duration, media_format* format, const void** infoBuffer,
709 	size_t* infoSize) const
710 {
711 	TRACE("AVFormatReader::StreamCookie::GetStreamInfo(%ld)\n",
712 		VirtualIndex());
713 
714 	double frameRate = FrameRate();
715 	TRACE("  frameRate: %.4f\n", frameRate);
716 
717 	// TODO: This is obviously not working correctly for all stream types...
718 	// It seems that the calculations here are correct, because they work
719 	// for a couple of streams and are in line with the documentation, but
720 	// unfortunately, libavformat itself seems to set the time_base and
721 	// duration wrongly sometimes. :-(
722 	if ((int64)fStream->duration != kNoPTSValue) {
723 		*duration = (bigtime_t)(1000000LL * fStream->duration
724 			* fStream->time_base.num / fStream->time_base.den);
725 		TRACE("  stream duration: %lld, time_base %.4f (%d/%d)\n",
726 			fStream->duration, av_q2d(fStream->time_base),
727 			fStream->time_base.num, fStream->time_base.den);
728 	} else if ((int64)fContext->duration != kNoPTSValue) {
729 		*duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE);
730 		TRACE("  stream duration: %lld (from AVFormatContext)\n",
731 			*duration);
732 	} else {
733 		*duration = 0;
734 		TRACE("  stream duration: N/A\n");
735 	}
736 
737 	TRACE("  duration: %lld or %.2fs\n", *duration, *duration / 1000000.0);
738 
739 	*frameCount = fStream->nb_frames;
740 	if (*frameCount == 0) {
741 		// Calculate from duration and frame rate
742 		*frameCount = (int64)(*duration * frameRate / 1000000LL);
743 		TRACE("  frameCount (calculated): %lld\n", *frameCount);
744 	} else
745 		TRACE("  frameCount: %lld\n", *frameCount);
746 
747 	*format = fFormat;
748 
749 	*infoBuffer = fStream->codec->extradata;
750 	*infoSize = fStream->codec->extradata_size;
751 
752 	return B_OK;
753 }
754 
755 
756 status_t
757 AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame,
758 	bigtime_t* time)
759 {
760 	if (fContext == NULL || fStream == NULL)
761 		return B_NO_INIT;
762 
763 	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) {
764 		TRACE_SEEK("AVFormatReader::StreamCookie::Seek() - "
765 			"B_MEDIA_SEEK_CLOSEST_FORWARD not supported.\n");
766 		return B_NOT_SUPPORTED;
767 	}
768 
769 	TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, "
770 		"%lld)\n", VirtualIndex(),
771 		(flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
772 		(flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
773 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
774 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
775 		*frame, *time);
776 
777 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
778 		*time = (bigtime_t)(*frame * 1000000LL / FrameRate());
779 
780 #if 0
781 	// This happens in ffplay.c:
782 
783 	int64_t pos = get_master_clock(cur_stream);
784 		// The master clock seems to be the current system time
785 		// with an offset for the current PTS value of the respective
786 		// stream.
787 	pos += incr;
788 		// depends on the seek direction...
789 
790 	pos = (int64_t)(pos * AV_TIME_BASE);
791 	uint32_t seekFlags = incr < 0 ? AVSEEK_FLAG_BACKWARD : 0;
792 
793 	pos = av_rescale_q(pos, AV_TIME_BASE_Q, fStream->time_base);
794 
795 	ret = av_seek_frame(fContext, Index(), pos, seekFlags);
796 #endif
797 
798 
799 	int64_t timeStamp;
800 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
801 		// Can use frame, because stream timeStamp is actually in frame
802 		// units.
803 		timeStamp = *frame;
804 	} else {
805 		timeStamp = *time * fStream->time_base.num
806 			/ ((int64_t)fStream->time_base.den * 1000000);
807 	}
808 
809 	TRACE_SEEK("  time: %.5fs -> %lld, current DTS: %lld (time_base: %d/%d)\n",
810 		*time / 1000000.0, timeStamp, fStream->cur_dts, fStream->time_base.num,
811 		fStream->time_base.den);
812 
813 	if (av_seek_frame(fContext, Index(), timeStamp, 0) < 0) {
814 		TRACE_SEEK("  av_seek_frame() failed.\n");
815 		return B_ERROR;
816 	}
817 
818 	// Our last packet is toast in any case.
819 	av_free_packet(&fPacket);
820 	fReusePacket = false;
821 
822 	return B_OK;
823 }
824 
825 
826 status_t
827 AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame,
828 	bigtime_t* time) const
829 {
830 	if (fContext == NULL || fStream == NULL)
831 		return B_NO_INIT;
832 
833 	TRACE_SEEK("AVFormatReader::StreamCookie::FindKeyFrame(%ld, %s %s %s %s, "
834 		"%lld, %lld)\n", VirtualIndex(),
835 		(flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
836 		(flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
837 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
838 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
839 		*frame, *time);
840 
841 	double frameRate = FrameRate();
842 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
843 		*time = (bigtime_t)(*frame * 1000000LL / frameRate);
844 
845 	int64_t timeStamp;
846 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
847 		// Can use frame, because stream timeStamp is actually in frame
848 		// units.
849 		timeStamp = *frame;
850 	} else {
851 		timeStamp = *time * fStream->time_base.num
852 			/ ((int64_t)fStream->time_base.den * 1000000);
853 	}
854 
855 	TRACE_SEEK("  time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 1000000.0,
856 		timeStamp, fStream->time_base.num, fStream->time_base.den);
857 
858 	int searchFlags = AVSEEK_FLAG_BACKWARD;
859 	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
860 		searchFlags = 0;
861 
862 	int index = av_index_search_timestamp(fStream, timeStamp, searchFlags);
863 	if (index < 0) {
864 		TRACE_SEEK("  av_index_search_timestamp() failed.\n");
865 		// Just seek to the beginning of the stream and assume it is a
866 		// keyframe...
867 		*frame = 0;
868 		*time = 0;
869 		return B_OK;
870 	}
871 
872 	const AVIndexEntry& entry = fStream->index_entries[index];
873 	timeStamp = entry.timestamp;
874 	*time = (bigtime_t)(timeStamp * 1000000 * fStream->time_base.num
875 		/ fStream->time_base.den);
876 
877 	TRACE_SEEK("  seeked time: %.2fs (%lld)\n", *time / 1000000.0, timeStamp);
878 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
879 		*frame = timeStamp;//*time * frameRate / 1000000LL;
880 		TRACE_SEEK("  seeked frame: %lld\n", *frame);
881 	}
882 
883 	return B_OK;
884 }
885 
886 
887 status_t
888 AVFormatReader::StreamCookie::GetNextChunk(const void** chunkBuffer,
889 	size_t* chunkSize, media_header* mediaHeader)
890 {
891 	TRACE_PACKET("AVFormatReader::StreamCookie::GetNextChunk()\n");
892 
893 	// Get the last stream DTS before reading the next packet, since
894 	// then it points to that one.
895 	int64 lastStreamDTS = fStream->cur_dts;
896 
897 	status_t ret = _NextPacket(false);
898 	if (ret != B_OK) {
899 		*chunkBuffer = NULL;
900 		*chunkSize = 0;
901 		return ret;
902 	}
903 
904 	// NOTE: AVPacket has a field called "convergence_duration", for which
905 	// the documentation is quite interesting. It sounds like it could be
906 	// used to know the time until the next I-Frame in streams that don't
907 	// let you know the position of keyframes in another way (like through
908 	// the index).
909 
910 	// According to libavformat documentation, fPacket is valid until the
911 	// next call to av_read_frame(). This is what we want and we can share
912 	// the memory with the least overhead.
913 	*chunkBuffer = fPacket.data;
914 	*chunkSize = fPacket.size;
915 
916 	if (mediaHeader != NULL) {
917 		mediaHeader->type = fFormat.type;
918 		mediaHeader->buffer = 0;
919 		mediaHeader->destination = -1;
920 		mediaHeader->time_source = -1;
921 		mediaHeader->size_used = fPacket.size;
922 		if (fPacket.pts != kNoPTSValue) {
923 //TRACE("  PTS: %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n",
924 //fPacket.pts, fStream->time_base.num, fStream->time_base.den,
925 //fStream->cur_dts);
926 			mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts
927 				* fStream->time_base.num / fStream->time_base.den);
928 		} else {
929 //TRACE("  PTS (stream): %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n",
930 //lastStreamDTS, fStream->time_base.num, fStream->time_base.den,
931 //fStream->cur_dts);
932 			mediaHeader->start_time = (bigtime_t)(1000000.0 * lastStreamDTS
933 				* fStream->time_base.num / fStream->time_base.den);
934 		}
935 		mediaHeader->file_pos = fPacket.pos;
936 		mediaHeader->data_offset = 0;
937 		switch (mediaHeader->type) {
938 			case B_MEDIA_RAW_AUDIO:
939 				break;
940 			case B_MEDIA_ENCODED_AUDIO:
941 				mediaHeader->u.encoded_audio.buffer_flags
942 					= (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
943 				break;
944 			case B_MEDIA_RAW_VIDEO:
945 				mediaHeader->u.raw_video.line_count
946 					= fFormat.u.raw_video.display.line_count;
947 				break;
948 			case B_MEDIA_ENCODED_VIDEO:
949 				mediaHeader->u.encoded_video.field_flags
950 					= (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
951 				mediaHeader->u.encoded_video.line_count
952 					= fFormat.u.encoded_video.output.display.line_count;
953 				break;
954 			default:
955 				break;
956 		}
957 	}
958 
959 	return B_OK;
960 }
961 
962 
963 // #pragma mark -
964 
965 
966 /*static*/ int
967 AVFormatReader::StreamCookie::_Read(void* cookie, uint8* buffer,
968 	int bufferSize)
969 {
970 	TRACE_IO("AVFormatReader::StreamCookie::_Read(%p, %p, %d)\n",
971 		cookie, buffer, bufferSize);
972 
973 	StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie);
974 
975 	BAutolock _(stream->fStreamLock);
976 
977 	if (stream->fPosition != stream->fSource->Position()) {
978 		off_t position
979 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
980 		if (position != stream->fPosition)
981 			return -1;
982 	}
983 
984 	ssize_t read = stream->fSource->Read(buffer, bufferSize);
985 	if (read > 0)
986 		stream->fPosition += read;
987 
988 	TRACE_IO("  read: %ld\n", read);
989 	return (int)read;
990 
991 }
992 
993 
994 /*static*/ off_t
995 AVFormatReader::StreamCookie::_Seek(void* cookie, off_t offset, int whence)
996 {
997 	TRACE_IO("AVFormatReader::StreamCookie::_Seek(%p, %lld, %d)\n",
998 		cookie, offset, whence);
999 
1000 	StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie);
1001 
1002 	BAutolock _(stream->fStreamLock);
1003 
1004 	// Support for special file size retrieval API without seeking
1005 	// anywhere:
1006 	if (whence == AVSEEK_SIZE) {
1007 		off_t size;
1008 		if (stream->fSource->GetSize(&size) == B_OK)
1009 			return size;
1010 		return -1;
1011 	}
1012 
1013 	// If not requested to seek to an absolute position, we need to
1014 	// confirm that the stream is currently at the position that we
1015 	// think it is.
1016 	if (whence != SEEK_SET
1017 		&& stream->fPosition != stream->fSource->Position()) {
1018 		off_t position
1019 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
1020 		if (position != stream->fPosition)
1021 			return -1;
1022 	}
1023 
1024 	off_t position = stream->fSource->Seek(offset, whence);
1025 	TRACE_IO("  position: %lld\n", position);
1026 	if (position < 0)
1027 		return -1;
1028 
1029 	stream->fPosition = position;
1030 
1031 	return position;
1032 }
1033 
1034 
1035 status_t
1036 AVFormatReader::StreamCookie::_NextPacket(bool reuse)
1037 {
1038 	TRACE_PACKET("AVFormatReader::StreamCookie::_NextPacket(%d)\n", reuse);
1039 
1040 	if (fReusePacket) {
1041 		// The last packet was marked for reuse, so we keep using it.
1042 		TRACE_PACKET("  re-using last packet\n");
1043 		fReusePacket = reuse;
1044 		return B_OK;
1045 	}
1046 
1047 	av_free_packet(&fPacket);
1048 
1049 	while (true) {
1050 		if (av_read_frame(fContext, &fPacket) < 0) {
1051 			// NOTE: Even though we may get the error for a different stream,
1052 			// av_read_frame() is not going to be successful from here on, so
1053 			// it doesn't matter
1054 			fReusePacket = false;
1055 			return B_LAST_BUFFER_ERROR;
1056 		}
1057 
1058 		if (fPacket.stream_index == Index())
1059 			break;
1060 
1061 		// This is a packet from another stream, ignore it.
1062 		av_free_packet(&fPacket);
1063 	}
1064 
1065 	// Mark this packet with the new reuse flag.
1066 	fReusePacket = reuse;
1067 	return B_OK;
1068 }
1069 
1070 
1071 // #pragma mark - AVFormatReader
1072 
1073 
1074 AVFormatReader::AVFormatReader()
1075 	:
1076 	fStreams(NULL),
1077 	fStreamLock("stream lock")
1078 {
1079 	TRACE("AVFormatReader::AVFormatReader\n");
1080 }
1081 
1082 
1083 AVFormatReader::~AVFormatReader()
1084 {
1085 	TRACE("AVFormatReader::~AVFormatReader\n");
1086 	if (fStreams != NULL) {
1087 		delete fStreams[0];
1088 		delete[] fStreams;
1089 	}
1090 }
1091 
1092 
1093 // #pragma mark -
1094 
1095 
1096 const char*
1097 AVFormatReader::Copyright()
1098 {
1099 // TODO: Could not find the equivalent in libavformat >= version 53.
1100 //	if (fStreams != NULL && fStreams[0] != NULL)
1101 //		return fStreams[0]->Context()->copyright;
1102 	// TODO: Return copyright of the file instead!
1103 	return "Copyright 2009, Stephan Aßmus";
1104 }
1105 
1106 
1107 status_t
1108 AVFormatReader::Sniff(int32* _streamCount)
1109 {
1110 	TRACE("AVFormatReader::Sniff\n");
1111 
1112 	BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1113 	if (source == NULL) {
1114 		TRACE("  not a BPositionIO, but we need it to be one.\n");
1115 		return B_NOT_SUPPORTED;
1116 	}
1117 
1118 	StreamCookie* stream = new(std::nothrow) StreamCookie(source,
1119 		&fStreamLock);
1120 	if (stream == NULL) {
1121 		ERROR("AVFormatReader::Sniff() - failed to allocate StreamCookie\n");
1122 		return B_NO_MEMORY;
1123 	}
1124 
1125 	ObjectDeleter<StreamCookie> streamDeleter(stream);
1126 
1127 	status_t ret = stream->Open();
1128 	if (ret != B_OK) {
1129 		TRACE("  failed to detect stream: %s\n", strerror(ret));
1130 		return ret;
1131 	}
1132 
1133 	delete[] fStreams;
1134 	fStreams = NULL;
1135 
1136 	int32 streamCount = stream->CountStreams();
1137 	if (streamCount == 0) {
1138 		TRACE("  failed to detect any streams: %s\n", strerror(ret));
1139 		return B_ERROR;
1140 	}
1141 
1142 	fStreams = new(std::nothrow) StreamCookie*[streamCount];
1143 	if (fStreams == NULL) {
1144 		ERROR("AVFormatReader::Sniff() - failed to allocate streams\n");
1145 		return B_NO_MEMORY;
1146 	}
1147 
1148 	memset(fStreams, 0, sizeof(StreamCookie*) * streamCount);
1149 	fStreams[0] = stream;
1150 	streamDeleter.Detach();
1151 
1152 	#ifdef TRACE_AVFORMAT_READER
1153 	dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0);
1154 	#endif
1155 
1156 	if (_streamCount != NULL)
1157 		*_streamCount = streamCount;
1158 
1159 	return B_OK;
1160 }
1161 
1162 
1163 void
1164 AVFormatReader::GetFileFormatInfo(media_file_format* mff)
1165 {
1166 	TRACE("AVFormatReader::GetFileFormatInfo\n");
1167 
1168 	if (fStreams == NULL)
1169 		return;
1170 
1171 	// The first cookie is always there!
1172 	const AVFormatContext* context = fStreams[0]->Context();
1173 
1174 	if (context == NULL || context->iformat == NULL) {
1175 		TRACE("  no AVFormatContext or AVInputFormat!\n");
1176 		return;
1177 	}
1178 
1179 	const DemuxerFormat* format = demuxer_format_for(context->iformat);
1180 
1181 	mff->capabilities = media_file_format::B_READABLE
1182 		| media_file_format::B_KNOWS_ENCODED_VIDEO
1183 		| media_file_format::B_KNOWS_ENCODED_AUDIO
1184 		| media_file_format::B_IMPERFECTLY_SEEKABLE;
1185 
1186 	if (format != NULL) {
1187 		// TODO: Check if AVInputFormat has audio only and then use
1188 		// format->audio_family!
1189 		mff->family = format->video_family;
1190 	} else {
1191 		TRACE("  no DemuxerFormat for AVInputFormat!\n");
1192 		mff->family = B_MISC_FORMAT_FAMILY;
1193 	}
1194 
1195 	mff->version = 100;
1196 
1197 	if (format != NULL) {
1198 		strcpy(mff->mime_type, format->mime_type);
1199 	} else {
1200 		// TODO: Would be nice to be able to provide this from AVInputFormat,
1201 		// maybe by extending the FFmpeg code itself (all demuxers).
1202 		strcpy(mff->mime_type, "");
1203 	}
1204 
1205 	if (context->iformat->extensions != NULL)
1206 		strcpy(mff->file_extension, context->iformat->extensions);
1207 	else {
1208 		TRACE("  no file extensions for AVInputFormat.\n");
1209 		strcpy(mff->file_extension, "");
1210 	}
1211 
1212 	if (context->iformat->name != NULL)
1213 		strcpy(mff->short_name,  context->iformat->name);
1214 	else {
1215 		TRACE("  no short name for AVInputFormat.\n");
1216 		strcpy(mff->short_name, "");
1217 	}
1218 
1219 	if (context->iformat->long_name != NULL)
1220 		strcpy(mff->pretty_name, context->iformat->long_name);
1221 	else {
1222 		if (format != NULL)
1223 			strcpy(mff->pretty_name, format->pretty_name);
1224 		else
1225 			strcpy(mff->pretty_name, "");
1226 	}
1227 }
1228 
1229 
1230 // #pragma mark -
1231 
1232 
1233 status_t
1234 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie)
1235 {
1236 	TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex);
1237 
1238 	BAutolock _(fStreamLock);
1239 
1240 	if (fStreams == NULL)
1241 		return B_NO_INIT;
1242 
1243 	if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams())
1244 		return B_BAD_INDEX;
1245 
1246 	if (_cookie == NULL)
1247 		return B_BAD_VALUE;
1248 
1249 	StreamCookie* cookie = fStreams[streamIndex];
1250 	if (cookie == NULL) {
1251 		// Allocate the cookie
1252 		BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1253 		if (source == NULL) {
1254 			TRACE("  not a BPositionIO, but we need it to be one.\n");
1255 			return B_NOT_SUPPORTED;
1256 		}
1257 
1258 		cookie = new(std::nothrow) StreamCookie(source, &fStreamLock);
1259 		if (cookie == NULL) {
1260 			ERROR("AVFormatReader::Sniff() - failed to allocate "
1261 				"StreamCookie\n");
1262 			return B_NO_MEMORY;
1263 		}
1264 
1265 		status_t ret = cookie->Open();
1266 		if (ret != B_OK) {
1267 			TRACE("  stream failed to open: %s\n", strerror(ret));
1268 			delete cookie;
1269 			return ret;
1270 		}
1271 	}
1272 
1273 	status_t ret = cookie->Init(streamIndex);
1274 	if (ret != B_OK) {
1275 		TRACE("  stream failed to initialize: %s\n", strerror(ret));
1276 		// NOTE: Never delete the first stream!
1277 		if (streamIndex != 0)
1278 			delete cookie;
1279 		return ret;
1280 	}
1281 
1282 	fStreams[streamIndex] = cookie;
1283 	*_cookie = cookie;
1284 
1285 	return B_OK;
1286 }
1287 
1288 
1289 status_t
1290 AVFormatReader::FreeCookie(void *_cookie)
1291 {
1292 	BAutolock _(fStreamLock);
1293 
1294 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1295 
1296 	// NOTE: Never delete the first cookie!
1297 	if (cookie != NULL && cookie->VirtualIndex() != 0) {
1298 		if (fStreams != NULL)
1299 			fStreams[cookie->VirtualIndex()] = NULL;
1300 		delete cookie;
1301 	}
1302 
1303 	return B_OK;
1304 }
1305 
1306 
1307 // #pragma mark -
1308 
1309 
1310 status_t
1311 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
1312 	bigtime_t* duration, media_format* format, const void** infoBuffer,
1313 	size_t* infoSize)
1314 {
1315 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1316 	return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer,
1317 		infoSize);
1318 }
1319 
1320 
1321 status_t
1322 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame,
1323 	bigtime_t* time)
1324 {
1325 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1326 	return cookie->Seek(seekTo, frame, time);
1327 }
1328 
1329 
1330 status_t
1331 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame,
1332 	bigtime_t* time)
1333 {
1334 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1335 	return cookie->FindKeyFrame(flags, frame, time);
1336 }
1337 
1338 
1339 status_t
1340 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer,
1341 	size_t* chunkSize, media_header* mediaHeader)
1342 {
1343 	StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
1344 	return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
1345 }
1346 
1347 
1348