xref: /haiku/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp (revision 23d878482ed22e55dad6d1fca1df7bea42eb157c)
1 /*
2  * Copyright 2009-2010, 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...) printf(a)
35 #	define TRACE_FIND(a...)
36 #	define TRACE_PACKET(a...)
37 #else
38 #	define TRACE(a...)
39 #	define TRACE_IO(a...)
40 #	define TRACE_SEEK(a...)
41 #	define TRACE_FIND(a...)
42 #	define TRACE_PACKET(a...)
43 #endif
44 
45 #define ERROR(a...) fprintf(stderr, a)
46 
47 
48 static const int64 kNoPTSValue = 0x8000000000000000LL;
49 	// NOTE: For some reasons, I have trouble with the avcodec.h define:
50 	// #define AV_NOPTS_VALUE          INT64_C(0x8000000000000000)
51 	// INT64_C is not defined here.
52 
53 
54 static uint32
55 avformat_to_beos_format(SampleFormat format)
56 {
57 	switch (format) {
58 		case SAMPLE_FMT_U8: return media_raw_audio_format::B_AUDIO_UCHAR;
59 		case SAMPLE_FMT_S16: return media_raw_audio_format::B_AUDIO_SHORT;
60 		case SAMPLE_FMT_S32: return media_raw_audio_format::B_AUDIO_INT;
61 		case SAMPLE_FMT_FLT: return media_raw_audio_format::B_AUDIO_FLOAT;
62 		case SAMPLE_FMT_DBL: return media_raw_audio_format::B_AUDIO_DOUBLE;
63 		default:
64 			break;
65 	}
66 	return 0;
67 }
68 
69 
70 static uint32
71 avformat_to_beos_byte_order(SampleFormat format)
72 {
73 	// TODO: Huh?
74 	return B_MEDIA_HOST_ENDIAN;
75 }
76 
77 
78 static void
79 avdictionary_to_message(AVDictionary* dictionary, BMessage* message)
80 {
81 	if (dictionary == NULL)
82 		return;
83 
84 	AVDictionaryEntry* entry = NULL;
85 	while ((entry = av_dict_get(dictionary, "", entry,
86 		AV_METADATA_IGNORE_SUFFIX))) {
87 		// convert entry keys into something more meaningful using the names from
88 		// id3v2.c
89 		if (strcmp(entry->key, "TALB") == 0 || strcmp(entry->key, "TAL") == 0)
90 			message->AddString("album", entry->value);
91 		else if (strcmp(entry->key, "TCOM") == 0)
92 			message->AddString("composer", entry->value);
93 		else if (strcmp(entry->key, "TCON") == 0 || strcmp(entry->key, "TCO") == 0)
94 			message->AddString("genre", entry->value);
95 		else if (strcmp(entry->key, "TCOP") == 0)
96 			message->AddString("copyright", entry->value);
97 		else if (strcmp(entry->key, "TDRL") == 0 || strcmp(entry->key, "TDRC") == 0)
98 			message->AddString("date", entry->value);
99 		else if (strcmp(entry->key, "TENC") == 0 || strcmp(entry->key, "TEN") == 0)
100 			message->AddString("encoded_by", entry->value);
101 		else if (strcmp(entry->key, "TIT2") == 0 || strcmp(entry->key, "TT2") == 0)
102 			message->AddString("title", entry->value);
103 		else if (strcmp(entry->key, "TLAN") == 0)
104 			message->AddString("language", entry->value);
105 		else if (strcmp(entry->key, "TPE1") == 0 || strcmp(entry->key, "TP1") == 0)
106 			message->AddString("artist", entry->value);
107 		else if (strcmp(entry->key, "TPE2") == 0 || strcmp(entry->key, "TP2") == 0)
108 			message->AddString("album_artist", entry->value);
109 		else if (strcmp(entry->key, "TPE3") == 0 || strcmp(entry->key, "TP3") == 0)
110 			message->AddString("performer", entry->value);
111 		else if (strcmp(entry->key, "TPOS") == 0)
112 			message->AddString("disc", entry->value);
113 		else if (strcmp(entry->key, "TPUB") == 0)
114 			message->AddString("publisher", entry->value);
115 		else if (strcmp(entry->key, "TRCK") == 0 || strcmp(entry->key, "TRK") == 0)
116 			message->AddString("track", entry->value);
117 		else if (strcmp(entry->key, "TSOA") == 0)
118 			message->AddString("album-sort", entry->value);
119 		else if (strcmp(entry->key, "TSOP") == 0)
120 			message->AddString("artist-sort", entry->value);
121 		else if (strcmp(entry->key, "TSOT") == 0)
122 			message->AddString("title-sort", entry->value);
123 		else if (strcmp(entry->key, "TSSE") == 0)
124 			message->AddString("encoder", entry->value);
125 		else if (strcmp(entry->key, "TYER") == 0)
126 			message->AddString("year", entry->value);
127 		else
128 			message->AddString(entry->key, entry->value);
129 	}
130 }
131 
132 
133 // #pragma mark - StreamBase
134 
135 
136 class StreamBase {
137 public:
138 								StreamBase(BPositionIO* source,
139 									BLocker* sourceLock, BLocker* streamLock);
140 	virtual						~StreamBase();
141 
142 	// Init an indivual AVFormatContext
143 			status_t			Open();
144 
145 	// Setup this stream to point to the AVStream at the given streamIndex.
146 	virtual	status_t			Init(int32 streamIndex);
147 
148 	inline	const AVFormatContext* Context() const
149 									{ return fContext; }
150 			int32				Index() const;
151 			int32				CountStreams() const;
152 			int32				StreamIndexFor(int32 virtualIndex) const;
153 	inline	int32				VirtualIndex() const
154 									{ return fVirtualIndex; }
155 
156 			double				FrameRate() const;
157 			bigtime_t			Duration() const;
158 
159 	virtual	status_t			Seek(uint32 flags, int64* frame,
160 									bigtime_t* time);
161 
162 			status_t			GetNextChunk(const void** chunkBuffer,
163 									size_t* chunkSize,
164 									media_header* mediaHeader);
165 
166 protected:
167 	// I/O hooks for libavformat, cookie will be a Stream instance.
168 	// Since multiple StreamCookies use the same BPositionIO source, they
169 	// maintain the position individually, and may need to seek the source
170 	// if it does not match anymore in _Read().
171 	// TODO: This concept prevents the use of a plain BDataIO that is not
172 	// seekable. There is a version of AVFormatReader in the SVN history
173 	// which implements packet buffering for other streams when reading
174 	// packets. To support non-seekable network streams for example, this
175 	// code should be resurrected. It will make handling seekable streams,
176 	// especially from different threads that read from totally independent
177 	// positions in the stream (aggressive pre-buffering perhaps), a lot
178 	// more difficult with potentially large memory overhead.
179 	static	int					_Read(void* cookie, uint8* buffer,
180 									int bufferSize);
181 	static	off_t				_Seek(void* cookie, off_t offset, int whence);
182 
183 			status_t			_NextPacket(bool reuse);
184 
185 			int64_t				_ConvertToStreamTimeBase(bigtime_t time) const;
186 			bigtime_t			_ConvertFromStreamTimeBase(int64_t time) const;
187 
188 protected:
189 			BPositionIO*		fSource;
190 			off_t				fPosition;
191 			// Since different threads may read from the source,
192 			// we need to protect the file position and I/O by a lock.
193 			BLocker*			fSourceLock;
194 
195 			BLocker*			fStreamLock;
196 
197 			AVFormatContext*	fContext;
198 			AVStream*			fStream;
199 			int32				fVirtualIndex;
200 
201 			media_format		fFormat;
202 
203 			AVIOContext*		fIOContext;
204 
205 			AVPacket			fPacket;
206 			bool				fReusePacket;
207 
208 			bool				fSeekByBytes;
209 			bool				fStreamBuildsIndexWhileReading;
210 };
211 
212 
213 StreamBase::StreamBase(BPositionIO* source, BLocker* sourceLock,
214 		BLocker* streamLock)
215 	:
216 	fSource(source),
217 	fPosition(0),
218 	fSourceLock(sourceLock),
219 
220 	fStreamLock(streamLock),
221 
222 	fContext(NULL),
223 	fStream(NULL),
224 	fVirtualIndex(-1),
225 	fIOContext(NULL),
226 
227 	fReusePacket(false),
228 
229 	fSeekByBytes(false),
230 	fStreamBuildsIndexWhileReading(false)
231 {
232 	// NOTE: Don't use streamLock here, it may not yet be initialized!
233 
234 	av_new_packet(&fPacket, 0);
235 	memset(&fFormat, 0, sizeof(media_format));
236 }
237 
238 
239 StreamBase::~StreamBase()
240 {
241 	av_free(fIOContext->buffer);
242 	av_free(fIOContext);
243 	av_free_packet(&fPacket);
244 	av_free(fContext);
245 }
246 
247 
248 status_t
249 StreamBase::Open()
250 {
251 	BAutolock _(fStreamLock);
252 
253 	// Init probing data
254 	size_t bufferSize = 32768;
255 	uint8* buffer = static_cast<uint8*>(av_malloc(bufferSize));
256 	if (buffer == NULL)
257 		return B_NO_MEMORY;
258 
259 	// Allocate I/O context with buffer and hook functions, pass ourself as
260 	// cookie.
261 	memset(buffer, 0, bufferSize);
262 	fIOContext = avio_alloc_context(buffer, bufferSize, 0, this, _Read, 0,
263 		_Seek);
264 	if (fIOContext == NULL) {
265 		TRACE("StreamBase::Open() - avio_alloc_context() failed!\n");
266 		return B_ERROR;
267 	}
268 
269 	fContext = avformat_alloc_context();
270 	fContext->pb = fIOContext;
271 
272 	// Allocate our context and probe the input format
273 	if (avformat_open_input(&fContext, "", NULL, NULL) < 0) {
274 		TRACE("StreamBase::Open() - avformat_open_input() failed!\n");
275 		// avformat_open_input() frees the context in case of failure
276 		return B_NOT_SUPPORTED;
277 	}
278 
279 	TRACE("StreamBase::Open() - "
280 		"avformat_open_input(): %s\n", fContext->iformat->name);
281 	TRACE("  flags:%s%s%s%s%s\n",
282 		(fContext->iformat->flags & AVFMT_GLOBALHEADER) ? " AVFMT_GLOBALHEADER" : "",
283 		(fContext->iformat->flags & AVFMT_NOTIMESTAMPS) ? " AVFMT_NOTIMESTAMPS" : "",
284 		(fContext->iformat->flags & AVFMT_GENERIC_INDEX) ? " AVFMT_GENERIC_INDEX" : "",
285 		(fContext->iformat->flags & AVFMT_TS_DISCONT) ? " AVFMT_TS_DISCONT" : "",
286 		(fContext->iformat->flags & AVFMT_VARIABLE_FPS) ? " AVFMT_VARIABLE_FPS" : ""
287 	);
288 
289 
290 	// Retrieve stream information
291 	if (avformat_find_stream_info(fContext, NULL) < 0) {
292 		TRACE("StreamBase::Open() - avformat_find_stream_info() failed!\n");
293 		return B_NOT_SUPPORTED;
294 	}
295 
296 	fSeekByBytes = (fContext->iformat->flags & AVFMT_TS_DISCONT) != 0;
297 	fStreamBuildsIndexWhileReading
298 		= (fContext->iformat->flags & AVFMT_GENERIC_INDEX) != 0
299 			|| fSeekByBytes;
300 
301 	TRACE("StreamBase::Open() - "
302 		"av_find_stream_info() success! Seeking by bytes: %d\n",
303 		fSeekByBytes);
304 
305 	return B_OK;
306 }
307 
308 
309 status_t
310 StreamBase::Init(int32 virtualIndex)
311 {
312 	BAutolock _(fStreamLock);
313 
314 	TRACE("StreamBase::Init(%ld)\n", virtualIndex);
315 
316 	if (fContext == NULL)
317 		return B_NO_INIT;
318 
319 	int32 streamIndex = StreamIndexFor(virtualIndex);
320 	if (streamIndex < 0) {
321 		TRACE("  bad stream index!\n");
322 		return B_BAD_INDEX;
323 	}
324 
325 	TRACE("  context stream index: %ld\n", streamIndex);
326 
327 	// We need to remember the virtual index so that
328 	// AVFormatReader::FreeCookie() can clear the correct stream entry.
329 	fVirtualIndex = virtualIndex;
330 
331 	// Make us point to the AVStream at streamIndex
332 	fStream = fContext->streams[streamIndex];
333 
334 // NOTE: Discarding other streams works for most, but not all containers,
335 // for example it does not work for the ASF demuxer. Since I don't know what
336 // other demuxer it breaks, let's just keep reading packets for unwanted
337 // streams, it just makes the _GetNextPacket() function slightly less
338 // efficient.
339 //	// Discard all other streams
340 //	for (unsigned i = 0; i < fContext->nb_streams; i++) {
341 //		if (i != (unsigned)streamIndex)
342 //			fContext->streams[i]->discard = AVDISCARD_ALL;
343 //	}
344 
345 	return B_OK;
346 }
347 
348 
349 int32
350 StreamBase::Index() const
351 {
352 	if (fStream != NULL)
353 		return fStream->index;
354 	return -1;
355 }
356 
357 
358 int32
359 StreamBase::CountStreams() const
360 {
361 	// Figure out the stream count. If the context has "AVPrograms", use
362 	// the first program (for now).
363 	// TODO: To support "programs" properly, the BMediaFile/Track API should
364 	// be extended accordingly. I guess programs are like TV channels in the
365 	// same satilite transport stream. Maybe call them "TrackGroups".
366 	if (fContext->nb_programs > 0) {
367 		// See libavformat/utils.c:dump_format()
368 		return fContext->programs[0]->nb_stream_indexes;
369 	}
370 	return fContext->nb_streams;
371 }
372 
373 
374 int32
375 StreamBase::StreamIndexFor(int32 virtualIndex) const
376 {
377 	// NOTE: See CountStreams()
378 	if (fContext->nb_programs > 0) {
379 		const AVProgram* program = fContext->programs[0];
380 		if (virtualIndex >= 0
381 			&& virtualIndex < (int32)program->nb_stream_indexes) {
382 			return program->stream_index[virtualIndex];
383 		}
384 	} else {
385 		if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams)
386 			return virtualIndex;
387 	}
388 	return -1;
389 }
390 
391 
392 double
393 StreamBase::FrameRate() const
394 {
395 	// TODO: Find a way to always calculate a correct frame rate...
396 	double frameRate = 1.0;
397 	switch (fStream->codec->codec_type) {
398 		case AVMEDIA_TYPE_AUDIO:
399 			frameRate = (double)fStream->codec->sample_rate;
400 			break;
401 		case AVMEDIA_TYPE_VIDEO:
402 			if (fStream->avg_frame_rate.den && fStream->avg_frame_rate.num)
403 				frameRate = av_q2d(fStream->avg_frame_rate);
404 			else if (fStream->r_frame_rate.den && fStream->r_frame_rate.num)
405 				frameRate = av_q2d(fStream->r_frame_rate);
406 			else if (fStream->time_base.den && fStream->time_base.num)
407 				frameRate = 1 / av_q2d(fStream->time_base);
408 			else if (fStream->codec->time_base.den
409 				&& fStream->codec->time_base.num) {
410 				frameRate = 1 / av_q2d(fStream->codec->time_base);
411 			}
412 
413 			// TODO: Fix up interlaced video for real
414 			if (frameRate == 50.0f)
415 				frameRate = 25.0f;
416 			break;
417 		default:
418 			break;
419 	}
420 	if (frameRate <= 0.0)
421 		frameRate = 1.0;
422 	return frameRate;
423 }
424 
425 
426 bigtime_t
427 StreamBase::Duration() const
428 {
429 	// TODO: This is not working correctly for all stream types...
430 	// It seems that the calculations here are correct, because they work
431 	// for a couple of streams and are in line with the documentation, but
432 	// unfortunately, libavformat itself seems to set the time_base and
433 	// duration wrongly sometimes. :-(
434 	if ((int64)fStream->duration != kNoPTSValue)
435 		return _ConvertFromStreamTimeBase(fStream->duration);
436 	else if ((int64)fContext->duration != kNoPTSValue)
437 		return (bigtime_t)fContext->duration;
438 
439 	return 0;
440 }
441 
442 
443 status_t
444 StreamBase::Seek(uint32 flags, int64* frame, bigtime_t* time)
445 {
446 	BAutolock _(fStreamLock);
447 
448 	if (fContext == NULL || fStream == NULL)
449 		return B_NO_INIT;
450 
451 	TRACE_SEEK("StreamBase::Seek(%ld,%s%s%s%s, %lld, "
452 		"%lld)\n", VirtualIndex(),
453 		(flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
454 		(flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
455 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD)
456 			? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
457 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD)
458 			? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
459 		*frame, *time);
460 
461 	double frameRate = FrameRate();
462 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
463 		// Seeking is always based on time, initialize it when client seeks
464 		// based on frame.
465 		*time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5);
466 	}
467 
468 	int64_t timeStamp = *time;
469 
470 	int searchFlags = AVSEEK_FLAG_BACKWARD;
471 	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
472 		searchFlags = 0;
473 
474 	if (fSeekByBytes) {
475 		searchFlags |= AVSEEK_FLAG_BYTE;
476 
477 		BAutolock _(fSourceLock);
478 		int64_t fileSize;
479 		if (fSource->GetSize(&fileSize) != B_OK)
480 			return B_NOT_SUPPORTED;
481 		int64_t duration = Duration();
482 		if (duration == 0)
483 			return B_NOT_SUPPORTED;
484 
485 		timeStamp = int64_t(fileSize * ((double)timeStamp / duration));
486 		if ((flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) != 0) {
487 			timeStamp -= 65536;
488 			if (timeStamp < 0)
489 				timeStamp = 0;
490 		}
491 
492 		bool seekAgain = true;
493 		bool seekForward = true;
494 		bigtime_t lastFoundTime = -1;
495 		int64_t closestTimeStampBackwards = -1;
496 		while (seekAgain) {
497 			if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp,
498 				INT64_MAX, searchFlags) < 0) {
499 				TRACE("  avformat_seek_file() (by bytes) failed.\n");
500 				return B_ERROR;
501 			}
502 			seekAgain = false;
503 
504 			// Our last packet is toast in any case. Read the next one so we
505 			// know where we really seeked.
506 			fReusePacket = false;
507 			if (_NextPacket(true) == B_OK) {
508 				while (fPacket.pts == kNoPTSValue) {
509 					fReusePacket = false;
510 					if (_NextPacket(true) != B_OK)
511 						return B_ERROR;
512 				}
513 				if (fPacket.pos >= 0)
514 					timeStamp = fPacket.pos;
515 				bigtime_t foundTime
516 					= _ConvertFromStreamTimeBase(fPacket.pts);
517 				if (foundTime != lastFoundTime) {
518 					lastFoundTime = foundTime;
519 					if (foundTime > *time) {
520 						if (closestTimeStampBackwards >= 0) {
521 							timeStamp = closestTimeStampBackwards;
522 							seekAgain = true;
523 							seekForward = false;
524 							continue;
525 						}
526 						int64_t diff = int64_t(fileSize
527 							* ((double)(foundTime - *time) / (2 * duration)));
528 						if (diff < 8192)
529 							break;
530 						timeStamp -= diff;
531 						TRACE_SEEK("  need to seek back (%lld) (time: %.2f "
532 							"-> %.2f)\n", timeStamp, *time / 1000000.0,
533 							foundTime / 1000000.0);
534 						if (timeStamp < 0)
535 							foundTime = 0;
536 						else {
537 							seekAgain = true;
538 							continue;
539 						}
540 					} else if (seekForward && foundTime < *time - 100000) {
541 						closestTimeStampBackwards = timeStamp;
542 						int64_t diff = int64_t(fileSize
543 							* ((double)(*time - foundTime) / (2 * duration)));
544 						if (diff < 8192)
545 							break;
546 						timeStamp += diff;
547 						TRACE_SEEK("  need to seek forward (%lld) (time: "
548 							"%.2f -> %.2f)\n", timeStamp, *time / 1000000.0,
549 							foundTime / 1000000.0);
550 						if (timeStamp > duration)
551 							foundTime = duration;
552 						else {
553 							seekAgain = true;
554 							continue;
555 						}
556 					}
557 				}
558 				TRACE_SEEK("  found time: %lld -> %lld (%.2f)\n", *time,
559 					foundTime, foundTime / 1000000.0);
560 				*time = foundTime;
561 				*frame = (uint64)(*time * frameRate / 1000000LL + 0.5);
562 				TRACE_SEEK("  seeked frame: %lld\n", *frame);
563 			} else {
564 				TRACE_SEEK("  _NextPacket() failed!\n");
565 				return B_ERROR;
566 			}
567 		}
568 	} else {
569 		// We may not get a PTS from the next packet after seeking, so
570 		// we try to get an expected time from the index.
571 		int64_t streamTimeStamp = _ConvertToStreamTimeBase(*time);
572 		int index = av_index_search_timestamp(fStream, streamTimeStamp,
573 			searchFlags);
574 		if (index < 0) {
575 			TRACE("  av_index_search_timestamp() failed\n");
576 		} else {
577 			if (index > 0) {
578 				const AVIndexEntry& entry = fStream->index_entries[index];
579 				streamTimeStamp = entry.timestamp;
580 			} else {
581 				// Some demuxers use the first index entry to store some
582 				// other information, like the total playing time for example.
583 				// Assume the timeStamp of the first entry is alays 0.
584 				// TODO: Handle start-time offset?
585 				streamTimeStamp = 0;
586 			}
587 			bigtime_t foundTime = _ConvertFromStreamTimeBase(streamTimeStamp);
588 			bigtime_t timeDiff = foundTime > *time
589 				? foundTime - *time : *time - foundTime;
590 
591 			if (timeDiff > 1000000
592 				&& (fStreamBuildsIndexWhileReading
593 					|| index == fStream->nb_index_entries - 1)) {
594 				// If the stream is building the index on the fly while parsing
595 				// it, we only have entries in the index for positions already
596 				// decoded, i.e. we cannot seek into the future. In that case,
597 				// just assume that we can seek where we want and leave
598 				// time/frame unmodified. Since successfully seeking one time
599 				// will generate index entries for the seeked to position, we
600 				// need to remember this in fStreamBuildsIndexWhileReading,
601 				// since when seeking back there will be later index entries,
602 				// but we still want to ignore the found entry.
603 				fStreamBuildsIndexWhileReading = true;
604 				TRACE_SEEK("  Not trusting generic index entry. "
605 					"(Current count: %d)\n", fStream->nb_index_entries);
606 			} else {
607 				// If we found a reasonably time, write it into *time.
608 				// After seeking, we will try to read the sought time from
609 				// the next packet. If the packet has no PTS value, we may
610 				// still have a more accurate time from the index lookup.
611 				*time = foundTime;
612 			}
613 		}
614 
615 		if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp, INT64_MAX,
616 				searchFlags) < 0) {
617 			TRACE("  avformat_seek_file() failed.\n");
618 			// Try to fall back to av_seek_frame()
619 			timeStamp = _ConvertToStreamTimeBase(timeStamp);
620 			if (av_seek_frame(fContext, fStream->index, timeStamp,
621 				searchFlags) < 0) {
622 				TRACE("  avformat_seek_frame() failed as well.\n");
623 				// Fall back to seeking to the beginning by bytes
624 				timeStamp = 0;
625 				if (av_seek_frame(fContext, fStream->index, timeStamp,
626 						AVSEEK_FLAG_BYTE) < 0) {
627 					TRACE("  avformat_seek_frame() by bytes failed as "
628 						"well.\n");
629 					// Do not propagate error in any case. We fail if we can't
630 					// read another packet.
631 				} else
632 					*time = 0;
633 			}
634 		}
635 
636 		// Our last packet is toast in any case. Read the next one so
637 		// we know where we really sought.
638 		bigtime_t foundTime = *time;
639 
640 		fReusePacket = false;
641 		if (_NextPacket(true) == B_OK) {
642 			if (fPacket.pts != kNoPTSValue)
643 				foundTime = _ConvertFromStreamTimeBase(fPacket.pts);
644 			else
645 				TRACE_SEEK("  no PTS in packet after seeking\n");
646 		} else
647 			TRACE_SEEK("  _NextPacket() failed!\n");
648 
649 		*time = foundTime;
650 		TRACE_SEEK("  sought time: %.2fs\n", *time / 1000000.0);
651 		*frame = (uint64)(*time * frameRate / 1000000.0 + 0.5);
652 		TRACE_SEEK("  sought frame: %lld\n", *frame);
653 	}
654 
655 	return B_OK;
656 }
657 
658 
659 status_t
660 StreamBase::GetNextChunk(const void** chunkBuffer,
661 	size_t* chunkSize, media_header* mediaHeader)
662 {
663 	BAutolock _(fStreamLock);
664 
665 	TRACE_PACKET("StreamBase::GetNextChunk()\n");
666 
667 	// Get the last stream DTS before reading the next packet, since
668 	// then it points to that one.
669 	int64 lastStreamDTS = fStream->cur_dts;
670 
671 	status_t ret = _NextPacket(false);
672 	if (ret != B_OK) {
673 		*chunkBuffer = NULL;
674 		*chunkSize = 0;
675 		return ret;
676 	}
677 
678 	// NOTE: AVPacket has a field called "convergence_duration", for which
679 	// the documentation is quite interesting. It sounds like it could be
680 	// used to know the time until the next I-Frame in streams that don't
681 	// let you know the position of keyframes in another way (like through
682 	// the index).
683 
684 	// According to libavformat documentation, fPacket is valid until the
685 	// next call to av_read_frame(). This is what we want and we can share
686 	// the memory with the least overhead.
687 	*chunkBuffer = fPacket.data;
688 	*chunkSize = fPacket.size;
689 
690 	if (mediaHeader != NULL) {
691 		mediaHeader->type = fFormat.type;
692 		mediaHeader->buffer = 0;
693 		mediaHeader->destination = -1;
694 		mediaHeader->time_source = -1;
695 		mediaHeader->size_used = fPacket.size;
696 		if (fPacket.pts != kNoPTSValue) {
697 //TRACE("  PTS: %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n",
698 //fPacket.pts, fStream->time_base.num, fStream->time_base.den,
699 //fStream->cur_dts);
700 			mediaHeader->start_time = _ConvertFromStreamTimeBase(fPacket.pts);
701 		} else {
702 //TRACE("  PTS (stream): %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n",
703 //lastStreamDTS, fStream->time_base.num, fStream->time_base.den,
704 //fStream->cur_dts);
705 			mediaHeader->start_time
706 				= _ConvertFromStreamTimeBase(lastStreamDTS);
707 		}
708 		mediaHeader->file_pos = fPacket.pos;
709 		mediaHeader->data_offset = 0;
710 		switch (mediaHeader->type) {
711 			case B_MEDIA_RAW_AUDIO:
712 				break;
713 			case B_MEDIA_ENCODED_AUDIO:
714 				mediaHeader->u.encoded_audio.buffer_flags
715 					= (fPacket.flags & AV_PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
716 				break;
717 			case B_MEDIA_RAW_VIDEO:
718 				mediaHeader->u.raw_video.line_count
719 					= fFormat.u.raw_video.display.line_count;
720 				break;
721 			case B_MEDIA_ENCODED_VIDEO:
722 				mediaHeader->u.encoded_video.field_flags
723 					= (fPacket.flags & AV_PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0;
724 				mediaHeader->u.encoded_video.line_count
725 					= fFormat.u.encoded_video.output.display.line_count;
726 				break;
727 			default:
728 				break;
729 		}
730 	}
731 
732 //	static bigtime_t pts[2];
733 //	static bigtime_t lastPrintTime = system_time();
734 //	static BLocker printLock;
735 //	if (fStream->index < 2) {
736 //		if (fPacket.pts != kNoPTSValue)
737 //			pts[fStream->index] = _ConvertFromStreamTimeBase(fPacket.pts);
738 //		printLock.Lock();
739 //		bigtime_t now = system_time();
740 //		if (now - lastPrintTime > 1000000) {
741 //			printf("PTS: %.4f/%.4f, diff: %.4f\r", pts[0] / 1000000.0,
742 //				pts[1] / 1000000.0, (pts[0] - pts[1]) / 1000000.0);
743 //			fflush(stdout);
744 //			lastPrintTime = now;
745 //		}
746 //		printLock.Unlock();
747 //	}
748 
749 	return B_OK;
750 }
751 
752 
753 // #pragma mark -
754 
755 
756 /*static*/ int
757 StreamBase::_Read(void* cookie, uint8* buffer, int bufferSize)
758 {
759 	StreamBase* stream = reinterpret_cast<StreamBase*>(cookie);
760 
761 	BAutolock _(stream->fSourceLock);
762 
763 	TRACE_IO("StreamBase::_Read(%p, %p, %d) position: %lld/%lld\n",
764 		cookie, buffer, bufferSize, stream->fPosition,
765 		stream->fSource->Position());
766 
767 	if (stream->fPosition != stream->fSource->Position()) {
768 		off_t position
769 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
770 		if (position != stream->fPosition)
771 			return -1;
772 	}
773 
774 	ssize_t read = stream->fSource->Read(buffer, bufferSize);
775 	if (read > 0)
776 		stream->fPosition += read;
777 
778 	TRACE_IO("  read: %ld\n", read);
779 	return (int)read;
780 
781 }
782 
783 
784 /*static*/ off_t
785 StreamBase::_Seek(void* cookie, off_t offset, int whence)
786 {
787 	TRACE_IO("StreamBase::_Seek(%p, %lld, %d)\n",
788 		cookie, offset, whence);
789 
790 	StreamBase* stream = reinterpret_cast<StreamBase*>(cookie);
791 
792 	BAutolock _(stream->fSourceLock);
793 
794 	// Support for special file size retrieval API without seeking
795 	// anywhere:
796 	if (whence == AVSEEK_SIZE) {
797 		off_t size;
798 		if (stream->fSource->GetSize(&size) == B_OK)
799 			return size;
800 		return -1;
801 	}
802 
803 	// If not requested to seek to an absolute position, we need to
804 	// confirm that the stream is currently at the position that we
805 	// think it is.
806 	if (whence != SEEK_SET
807 		&& stream->fPosition != stream->fSource->Position()) {
808 		off_t position
809 			= stream->fSource->Seek(stream->fPosition, SEEK_SET);
810 		if (position != stream->fPosition)
811 			return -1;
812 	}
813 
814 	off_t position = stream->fSource->Seek(offset, whence);
815 	TRACE_IO("  position: %lld\n", position);
816 	if (position < 0)
817 		return -1;
818 
819 	stream->fPosition = position;
820 
821 	return position;
822 }
823 
824 
825 status_t
826 StreamBase::_NextPacket(bool reuse)
827 {
828 	TRACE_PACKET("StreamBase::_NextPacket(%d)\n", reuse);
829 
830 	if (fReusePacket) {
831 		// The last packet was marked for reuse, so we keep using it.
832 		TRACE_PACKET("  re-using last packet\n");
833 		fReusePacket = reuse;
834 		return B_OK;
835 	}
836 
837 	av_free_packet(&fPacket);
838 
839 	while (true) {
840 		if (av_read_frame(fContext, &fPacket) < 0) {
841 			// NOTE: Even though we may get the error for a different stream,
842 			// av_read_frame() is not going to be successful from here on, so
843 			// it doesn't matter
844 			fReusePacket = false;
845 			return B_LAST_BUFFER_ERROR;
846 		}
847 
848 		if (fPacket.stream_index == Index())
849 			break;
850 
851 		// This is a packet from another stream, ignore it.
852 		av_free_packet(&fPacket);
853 	}
854 
855 	// Mark this packet with the new reuse flag.
856 	fReusePacket = reuse;
857 	return B_OK;
858 }
859 
860 
861 int64_t
862 StreamBase::_ConvertToStreamTimeBase(bigtime_t time) const
863 {
864 	int64 timeStamp = int64_t((double)time * fStream->time_base.den
865 		/ (1000000.0 * fStream->time_base.num) + 0.5);
866 	if (fStream->start_time != kNoPTSValue)
867 		timeStamp += fStream->start_time;
868 	return timeStamp;
869 }
870 
871 
872 bigtime_t
873 StreamBase::_ConvertFromStreamTimeBase(int64_t time) const
874 {
875 	if (fStream->start_time != kNoPTSValue)
876 		time -= fStream->start_time;
877 
878 	return bigtime_t(1000000.0 * time * fStream->time_base.num
879 		/ fStream->time_base.den + 0.5);
880 }
881 
882 
883 // #pragma mark - AVFormatReader::Stream
884 
885 
886 class AVFormatReader::Stream : public StreamBase {
887 public:
888 								Stream(BPositionIO* source,
889 									BLocker* streamLock);
890 	virtual						~Stream();
891 
892 	// Setup this stream to point to the AVStream at the given streamIndex.
893 	// This will also initialize the media_format.
894 	virtual	status_t			Init(int32 streamIndex);
895 
896 			status_t			GetMetaData(BMessage* data);
897 
898 	// Support for AVFormatReader
899 			status_t			GetStreamInfo(int64* frameCount,
900 									bigtime_t* duration, media_format* format,
901 									const void** infoBuffer,
902 									size_t* infoSize) const;
903 
904 			status_t			FindKeyFrame(uint32 flags, int64* frame,
905 									bigtime_t* time) const;
906 	virtual	status_t			Seek(uint32 flags, int64* frame,
907 									bigtime_t* time);
908 
909 private:
910 	mutable	BLocker				fLock;
911 
912 			struct KeyframeInfo {
913 				bigtime_t		requestedTime;
914 				int64			requestedFrame;
915 				bigtime_t		reportedTime;
916 				int64			reportedFrame;
917 				uint32			seekFlags;
918 			};
919 	mutable	KeyframeInfo		fLastReportedKeyframe;
920 	mutable	StreamBase*			fGhostStream;
921 };
922 
923 
924 
925 AVFormatReader::Stream::Stream(BPositionIO* source, BLocker* streamLock)
926 	:
927 	StreamBase(source, streamLock, &fLock),
928 	fLock("stream lock"),
929 	fGhostStream(NULL)
930 {
931 	fLastReportedKeyframe.requestedTime = 0;
932 	fLastReportedKeyframe.requestedFrame = 0;
933 	fLastReportedKeyframe.reportedTime = 0;
934 	fLastReportedKeyframe.reportedFrame = 0;
935 }
936 
937 
938 AVFormatReader::Stream::~Stream()
939 {
940 	delete fGhostStream;
941 }
942 
943 
944 status_t
945 AVFormatReader::Stream::Init(int32 virtualIndex)
946 {
947 	TRACE("AVFormatReader::Stream::Init(%ld)\n", virtualIndex);
948 
949 	status_t ret = StreamBase::Init(virtualIndex);
950 	if (ret != B_OK)
951 		return ret;
952 
953 	// Get a pointer to the AVCodecContext for the stream at streamIndex.
954 	AVCodecContext* codecContext = fStream->codec;
955 
956 #if 0
957 // stippi: Here I was experimenting with the question if some fields of the
958 // AVCodecContext change (or get filled out at all), if the AVCodec is opened.
959 	class CodecOpener {
960 	public:
961 		CodecOpener(AVCodecContext* context)
962 		{
963 			fCodecContext = context;
964 			AVCodec* codec = avcodec_find_decoder(context->codec_id);
965 			fCodecOpen = avcodec_open(context, codec) >= 0;
966 			if (!fCodecOpen)
967 				TRACE("  failed to open the codec!\n");
968 		}
969 		~CodecOpener()
970 		{
971 			if (fCodecOpen)
972 				avcodec_close(fCodecContext);
973 		}
974 	private:
975 		AVCodecContext*		fCodecContext;
976 		bool				fCodecOpen;
977 	} codecOpener(codecContext);
978 #endif
979 
980 	// initialize the media_format for this stream
981 	media_format* format = &fFormat;
982 	memset(format, 0, sizeof(media_format));
983 
984 	media_format_description description;
985 
986 	// Set format family and type depending on codec_type of the stream.
987 	switch (codecContext->codec_type) {
988 		case AVMEDIA_TYPE_AUDIO:
989 			if ((codecContext->codec_id >= CODEC_ID_PCM_S16LE)
990 				&& (codecContext->codec_id <= CODEC_ID_PCM_U8)) {
991 				TRACE("  raw audio\n");
992 				format->type = B_MEDIA_RAW_AUDIO;
993 				description.family = B_ANY_FORMAT_FAMILY;
994 				// This will then apparently be handled by the (built into
995 				// BMediaTrack) RawDecoder.
996 			} else {
997 				TRACE("  encoded audio\n");
998 				format->type = B_MEDIA_ENCODED_AUDIO;
999 				description.family = B_MISC_FORMAT_FAMILY;
1000 				description.u.misc.file_format = 'ffmp';
1001 			}
1002 			break;
1003 		case AVMEDIA_TYPE_VIDEO:
1004 			TRACE("  encoded video\n");
1005 			format->type = B_MEDIA_ENCODED_VIDEO;
1006 			description.family = B_MISC_FORMAT_FAMILY;
1007 			description.u.misc.file_format = 'ffmp';
1008 			break;
1009 		default:
1010 			TRACE("  unknown type\n");
1011 			format->type = B_MEDIA_UNKNOWN_TYPE;
1012 			return B_ERROR;
1013 			break;
1014 	}
1015 
1016 	if (format->type == B_MEDIA_RAW_AUDIO) {
1017 		// We cannot describe all raw-audio formats, some are unsupported.
1018 		switch (codecContext->codec_id) {
1019 			case CODEC_ID_PCM_S16LE:
1020 				format->u.raw_audio.format
1021 					= media_raw_audio_format::B_AUDIO_SHORT;
1022 				format->u.raw_audio.byte_order
1023 					= B_MEDIA_LITTLE_ENDIAN;
1024 				break;
1025 			case CODEC_ID_PCM_S16BE:
1026 				format->u.raw_audio.format
1027 					= media_raw_audio_format::B_AUDIO_SHORT;
1028 				format->u.raw_audio.byte_order
1029 					= B_MEDIA_BIG_ENDIAN;
1030 				break;
1031 			case CODEC_ID_PCM_U16LE:
1032 //				format->u.raw_audio.format
1033 //					= media_raw_audio_format::B_AUDIO_USHORT;
1034 //				format->u.raw_audio.byte_order
1035 //					= B_MEDIA_LITTLE_ENDIAN;
1036 				return B_NOT_SUPPORTED;
1037 				break;
1038 			case CODEC_ID_PCM_U16BE:
1039 //				format->u.raw_audio.format
1040 //					= media_raw_audio_format::B_AUDIO_USHORT;
1041 //				format->u.raw_audio.byte_order
1042 //					= B_MEDIA_BIG_ENDIAN;
1043 				return B_NOT_SUPPORTED;
1044 				break;
1045 			case CODEC_ID_PCM_S8:
1046 				format->u.raw_audio.format
1047 					= media_raw_audio_format::B_AUDIO_CHAR;
1048 				break;
1049 			case CODEC_ID_PCM_U8:
1050 				format->u.raw_audio.format
1051 					= media_raw_audio_format::B_AUDIO_UCHAR;
1052 				break;
1053 			default:
1054 				return B_NOT_SUPPORTED;
1055 				break;
1056 		}
1057 	} else {
1058 		if (description.family == B_MISC_FORMAT_FAMILY)
1059 			description.u.misc.codec = codecContext->codec_id;
1060 
1061 		BMediaFormats formats;
1062 		status_t status = formats.GetFormatFor(description, format);
1063 		if (status < B_OK)
1064 			TRACE("  formats.GetFormatFor() error: %s\n", strerror(status));
1065 
1066 		format->user_data_type = B_CODEC_TYPE_INFO;
1067 		*(uint32*)format->user_data = codecContext->codec_tag;
1068 		format->user_data[4] = 0;
1069 	}
1070 
1071 	format->require_flags = 0;
1072 	format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1073 
1074 	switch (format->type) {
1075 		case B_MEDIA_RAW_AUDIO:
1076 			format->u.raw_audio.frame_rate = (float)codecContext->sample_rate;
1077 			format->u.raw_audio.channel_count = codecContext->channels;
1078 			format->u.raw_audio.channel_mask = codecContext->channel_layout;
1079 			format->u.raw_audio.byte_order
1080 				= avformat_to_beos_byte_order(codecContext->sample_fmt);
1081 			format->u.raw_audio.format
1082 				= avformat_to_beos_format(codecContext->sample_fmt);
1083 			format->u.raw_audio.buffer_size = 0;
1084 
1085 			// Read one packet and mark it for later re-use. (So our first
1086 			// GetNextChunk() call does not read another packet.)
1087 			if (_NextPacket(true) == B_OK) {
1088 				TRACE("  successfully determined audio buffer size: %d\n",
1089 					fPacket.size);
1090 				format->u.raw_audio.buffer_size = fPacket.size;
1091 			}
1092 			break;
1093 
1094 		case B_MEDIA_ENCODED_AUDIO:
1095 			format->u.encoded_audio.bit_rate = codecContext->bit_rate;
1096 			format->u.encoded_audio.frame_size = codecContext->frame_size;
1097 			// Fill in some info about possible output format
1098 			format->u.encoded_audio.output
1099 				= media_multi_audio_format::wildcard;
1100 			format->u.encoded_audio.output.frame_rate
1101 				= (float)codecContext->sample_rate;
1102 			// Channel layout bits match in Be API and FFmpeg.
1103 			format->u.encoded_audio.output.channel_count
1104 				= codecContext->channels;
1105 			format->u.encoded_audio.multi_info.channel_mask
1106 				= codecContext->channel_layout;
1107 			format->u.encoded_audio.output.byte_order
1108 				= avformat_to_beos_byte_order(codecContext->sample_fmt);
1109 			format->u.encoded_audio.output.format
1110 				= avformat_to_beos_format(codecContext->sample_fmt);
1111 			if (codecContext->block_align > 0) {
1112 				format->u.encoded_audio.output.buffer_size
1113 					= codecContext->block_align;
1114 			} else {
1115 				format->u.encoded_audio.output.buffer_size
1116 					= codecContext->frame_size * codecContext->channels
1117 						* (format->u.encoded_audio.output.format
1118 							& media_raw_audio_format::B_AUDIO_SIZE_MASK);
1119 			}
1120 			break;
1121 
1122 		case B_MEDIA_ENCODED_VIDEO:
1123 // TODO: Specifying any of these seems to throw off the format matching
1124 // later on.
1125 //			format->u.encoded_video.avg_bit_rate = codecContext->bit_rate;
1126 //			format->u.encoded_video.max_bit_rate = codecContext->bit_rate
1127 //				+ codecContext->bit_rate_tolerance;
1128 
1129 //			format->u.encoded_video.encoding
1130 //				= media_encoded_video_format::B_ANY;
1131 
1132 //			format->u.encoded_video.frame_size = 1;
1133 //			format->u.encoded_video.forward_history = 0;
1134 //			format->u.encoded_video.backward_history = 0;
1135 
1136 			format->u.encoded_video.output.field_rate = FrameRate();
1137 			format->u.encoded_video.output.interlace = 1;
1138 
1139 			format->u.encoded_video.output.first_active = 0;
1140 			format->u.encoded_video.output.last_active
1141 				= codecContext->height - 1;
1142 				// TODO: Maybe libavformat actually provides that info
1143 				// somewhere...
1144 			format->u.encoded_video.output.orientation
1145 				= B_VIDEO_TOP_LEFT_RIGHT;
1146 
1147 			// Calculate the display aspect ratio
1148 			AVRational displayAspectRatio;
1149 		    if (codecContext->sample_aspect_ratio.num != 0) {
1150 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
1151 					codecContext->width
1152 						* codecContext->sample_aspect_ratio.num,
1153 					codecContext->height
1154 						* codecContext->sample_aspect_ratio.den,
1155 					1024 * 1024);
1156 				TRACE("  pixel aspect ratio: %d/%d, "
1157 					"display aspect ratio: %d/%d\n",
1158 					codecContext->sample_aspect_ratio.num,
1159 					codecContext->sample_aspect_ratio.den,
1160 					displayAspectRatio.num, displayAspectRatio.den);
1161 		    } else {
1162 				av_reduce(&displayAspectRatio.num, &displayAspectRatio.den,
1163 					codecContext->width, codecContext->height, 1024 * 1024);
1164 				TRACE("  no display aspect ratio (%d/%d)\n",
1165 					displayAspectRatio.num, displayAspectRatio.den);
1166 		    }
1167 			format->u.encoded_video.output.pixel_width_aspect
1168 				= displayAspectRatio.num;
1169 			format->u.encoded_video.output.pixel_height_aspect
1170 				= displayAspectRatio.den;
1171 
1172 			format->u.encoded_video.output.display.format
1173 				= pixfmt_to_colorspace(codecContext->pix_fmt);
1174 			format->u.encoded_video.output.display.line_width
1175 				= codecContext->width;
1176 			format->u.encoded_video.output.display.line_count
1177 				= codecContext->height;
1178 			TRACE("  width/height: %d/%d\n", codecContext->width,
1179 				codecContext->height);
1180 			format->u.encoded_video.output.display.bytes_per_row = 0;
1181 			format->u.encoded_video.output.display.pixel_offset = 0;
1182 			format->u.encoded_video.output.display.line_offset = 0;
1183 			format->u.encoded_video.output.display.flags = 0; // TODO
1184 
1185 			break;
1186 
1187 		default:
1188 			// This is an unknown format to us.
1189 			break;
1190 	}
1191 
1192 	// Add the meta data, if any
1193 	if (codecContext->extradata_size > 0) {
1194 		format->SetMetaData(codecContext->extradata,
1195 			codecContext->extradata_size);
1196 		TRACE("  extradata: %p\n", format->MetaData());
1197 	}
1198 
1199 	TRACE("  extradata_size: %d\n", codecContext->extradata_size);
1200 //	TRACE("  intra_matrix: %p\n", codecContext->intra_matrix);
1201 //	TRACE("  inter_matrix: %p\n", codecContext->inter_matrix);
1202 //	TRACE("  get_buffer(): %p\n", codecContext->get_buffer);
1203 //	TRACE("  release_buffer(): %p\n", codecContext->release_buffer);
1204 
1205 #ifdef TRACE_AVFORMAT_READER
1206 	char formatString[512];
1207 	if (string_for_format(*format, formatString, sizeof(formatString)))
1208 		TRACE("  format: %s\n", formatString);
1209 
1210 	uint32 encoding = format->Encoding();
1211 	TRACE("  encoding '%.4s'\n", (char*)&encoding);
1212 #endif
1213 
1214 	return B_OK;
1215 }
1216 
1217 
1218 status_t
1219 AVFormatReader::Stream::GetMetaData(BMessage* data)
1220 {
1221 	BAutolock _(&fLock);
1222 
1223 	avdictionary_to_message(fStream->metadata, data);
1224 
1225 	return B_OK;
1226 }
1227 
1228 
1229 status_t
1230 AVFormatReader::Stream::GetStreamInfo(int64* frameCount,
1231 	bigtime_t* duration, media_format* format, const void** infoBuffer,
1232 	size_t* infoSize) const
1233 {
1234 	BAutolock _(&fLock);
1235 
1236 	TRACE("AVFormatReader::Stream::GetStreamInfo(%ld)\n",
1237 		VirtualIndex());
1238 
1239 	double frameRate = FrameRate();
1240 	TRACE("  frameRate: %.4f\n", frameRate);
1241 
1242 	#ifdef TRACE_AVFORMAT_READER
1243 	if (fStream->start_time != kNoPTSValue) {
1244 		bigtime_t startTime = _ConvertFromStreamTimeBase(fStream->start_time);
1245 		TRACE("  start_time: %lld or %.5fs\n", startTime,
1246 			startTime / 1000000.0);
1247 		// TODO: Handle start time in FindKeyFrame() and Seek()?!
1248 	}
1249 	#endif // TRACE_AVFORMAT_READER
1250 
1251 	*duration = Duration();
1252 
1253 	TRACE("  duration: %lld or %.5fs\n", *duration, *duration / 1000000.0);
1254 
1255 	#if 0
1256 	if (fStream->nb_index_entries > 0) {
1257 		TRACE("  dump of index entries:\n");
1258 		int count = 5;
1259 		int firstEntriesCount = min_c(fStream->nb_index_entries, count);
1260 		int i = 0;
1261 		for (; i < firstEntriesCount; i++) {
1262 			AVIndexEntry& entry = fStream->index_entries[i];
1263 			bigtime_t timeGlobal = entry.timestamp;
1264 			bigtime_t timeNative = _ConvertFromStreamTimeBase(timeGlobal);
1265 			TRACE("    [%d] native: %.5fs global: %.5fs\n", i,
1266 				timeNative / 1000000.0f, timeGlobal / 1000000.0f);
1267 		}
1268 		if (fStream->nb_index_entries - count > i) {
1269 			i = fStream->nb_index_entries - count;
1270 			TRACE("    ...\n");
1271 			for (; i < fStream->nb_index_entries; i++) {
1272 				AVIndexEntry& entry = fStream->index_entries[i];
1273 				bigtime_t timeGlobal = entry.timestamp;
1274 				bigtime_t timeNative = _ConvertFromStreamTimeBase(timeGlobal);
1275 				TRACE("    [%d] native: %.5fs global: %.5fs\n", i,
1276 					timeNative / 1000000.0f, timeGlobal / 1000000.0f);
1277 			}
1278 		}
1279 	}
1280 	#endif
1281 
1282 	*frameCount = fStream->nb_frames;
1283 //	if (*frameCount == 0) {
1284 		// Calculate from duration and frame rate
1285 		*frameCount = (int64)(*duration * frameRate / 1000000LL);
1286 		TRACE("  frameCount calculated: %lld, from context: %lld\n",
1287 			*frameCount, fStream->nb_frames);
1288 //	} else
1289 //		TRACE("  frameCount: %lld\n", *frameCount);
1290 
1291 	*format = fFormat;
1292 
1293 	*infoBuffer = fStream->codec->extradata;
1294 	*infoSize = fStream->codec->extradata_size;
1295 
1296 	return B_OK;
1297 }
1298 
1299 
1300 status_t
1301 AVFormatReader::Stream::FindKeyFrame(uint32 flags, int64* frame,
1302 	bigtime_t* time) const
1303 {
1304 	BAutolock _(&fLock);
1305 
1306 	if (fContext == NULL || fStream == NULL)
1307 		return B_NO_INIT;
1308 
1309 	TRACE_FIND("AVFormatReader::Stream::FindKeyFrame(%ld,%s%s%s%s, "
1310 		"%lld, %lld)\n", VirtualIndex(),
1311 		(flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
1312 		(flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
1313 		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD)
1314 			? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
1315 		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD)
1316 			? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
1317 		*frame, *time);
1318 
1319 	bool inLastRequestedRange = false;
1320 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
1321 		if (fLastReportedKeyframe.reportedFrame
1322 			<= fLastReportedKeyframe.requestedFrame) {
1323 			inLastRequestedRange
1324 				= *frame >= fLastReportedKeyframe.reportedFrame
1325 					&& *frame <= fLastReportedKeyframe.requestedFrame;
1326 		} else {
1327 			inLastRequestedRange
1328 				= *frame >= fLastReportedKeyframe.requestedFrame
1329 					&& *frame <= fLastReportedKeyframe.reportedFrame;
1330 		}
1331 	} else if ((flags & B_MEDIA_SEEK_TO_FRAME) == 0) {
1332 		if (fLastReportedKeyframe.reportedTime
1333 			<= fLastReportedKeyframe.requestedTime) {
1334 			inLastRequestedRange
1335 				= *time >= fLastReportedKeyframe.reportedTime
1336 					&& *time <= fLastReportedKeyframe.requestedTime;
1337 		} else {
1338 			inLastRequestedRange
1339 				= *time >= fLastReportedKeyframe.requestedTime
1340 					&& *time <= fLastReportedKeyframe.reportedTime;
1341 		}
1342 	}
1343 
1344 	if (inLastRequestedRange) {
1345 		*frame = fLastReportedKeyframe.reportedFrame;
1346 		*time = fLastReportedKeyframe.reportedTime;
1347 		TRACE_FIND("  same as last reported keyframe\n");
1348 		return B_OK;
1349 	}
1350 
1351 	double frameRate = FrameRate();
1352 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
1353 		*time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5);
1354 
1355 	status_t ret;
1356 	if (fGhostStream == NULL) {
1357 		BAutolock _(fSourceLock);
1358 
1359 		fGhostStream = new(std::nothrow) StreamBase(fSource, fSourceLock,
1360 			&fLock);
1361 		if (fGhostStream == NULL) {
1362 			TRACE("  failed to allocate ghost stream\n");
1363 			return B_NO_MEMORY;
1364 		}
1365 
1366 		ret = fGhostStream->Open();
1367 		if (ret != B_OK) {
1368 			TRACE("  ghost stream failed to open: %s\n", strerror(ret));
1369 			return B_ERROR;
1370 		}
1371 
1372 		ret = fGhostStream->Init(fVirtualIndex);
1373 		if (ret != B_OK) {
1374 			TRACE("  ghost stream failed to init: %s\n", strerror(ret));
1375 			return B_ERROR;
1376 		}
1377 	}
1378 	fLastReportedKeyframe.requestedFrame = *frame;
1379 	fLastReportedKeyframe.requestedTime = *time;
1380 	fLastReportedKeyframe.seekFlags = flags;
1381 
1382 	ret = fGhostStream->Seek(flags, frame, time);
1383 	if (ret != B_OK) {
1384 		TRACE("  ghost stream failed to seek: %s\n", strerror(ret));
1385 		return B_ERROR;
1386 	}
1387 
1388 	fLastReportedKeyframe.reportedFrame = *frame;
1389 	fLastReportedKeyframe.reportedTime = *time;
1390 
1391 	TRACE_FIND("  found time: %.2fs\n", *time / 1000000.0);
1392 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
1393 		*frame = int64_t(*time * FrameRate() / 1000000.0 + 0.5);
1394 		TRACE_FIND("  found frame: %lld\n", *frame);
1395 	}
1396 
1397 	return B_OK;
1398 }
1399 
1400 
1401 status_t
1402 AVFormatReader::Stream::Seek(uint32 flags, int64* frame, bigtime_t* time)
1403 {
1404 	BAutolock _(&fLock);
1405 
1406 	if (fContext == NULL || fStream == NULL)
1407 		return B_NO_INIT;
1408 
1409 	// Put the old requested values into frame/time, since we already know
1410 	// that the sought frame/time will then match the reported values.
1411 	// TODO: Will not work if client changes seek flags (from backwards to
1412 	// forward or vice versa)!!
1413 	bool inLastRequestedRange = false;
1414 	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
1415 		if (fLastReportedKeyframe.reportedFrame
1416 			<= fLastReportedKeyframe.requestedFrame) {
1417 			inLastRequestedRange
1418 				= *frame >= fLastReportedKeyframe.reportedFrame
1419 					&& *frame <= fLastReportedKeyframe.requestedFrame;
1420 		} else {
1421 			inLastRequestedRange
1422 				= *frame >= fLastReportedKeyframe.requestedFrame
1423 					&& *frame <= fLastReportedKeyframe.reportedFrame;
1424 		}
1425 	} else if ((flags & B_MEDIA_SEEK_TO_FRAME) == 0) {
1426 		if (fLastReportedKeyframe.reportedTime
1427 			<= fLastReportedKeyframe.requestedTime) {
1428 			inLastRequestedRange
1429 				= *time >= fLastReportedKeyframe.reportedTime
1430 					&& *time <= fLastReportedKeyframe.requestedTime;
1431 		} else {
1432 			inLastRequestedRange
1433 				= *time >= fLastReportedKeyframe.requestedTime
1434 					&& *time <= fLastReportedKeyframe.reportedTime;
1435 		}
1436 	}
1437 
1438 	if (inLastRequestedRange) {
1439 		*frame = fLastReportedKeyframe.requestedFrame;
1440 		*time = fLastReportedKeyframe.requestedTime;
1441 		flags = fLastReportedKeyframe.seekFlags;
1442 	}
1443 
1444 	return StreamBase::Seek(flags, frame, time);
1445 }
1446 
1447 
1448 // #pragma mark - AVFormatReader
1449 
1450 
1451 AVFormatReader::AVFormatReader()
1452 	:
1453 	fStreams(NULL),
1454 	fSourceLock("source I/O lock")
1455 {
1456 	TRACE("AVFormatReader::AVFormatReader\n");
1457 }
1458 
1459 
1460 AVFormatReader::~AVFormatReader()
1461 {
1462 	TRACE("AVFormatReader::~AVFormatReader\n");
1463 	if (fStreams != NULL) {
1464 		// The client was supposed to call FreeCookie() on all
1465 		// allocated streams. Deleting the first stream is always
1466 		// prevented, we delete the other ones just in case.
1467 		int32 count = fStreams[0]->CountStreams();
1468 		for (int32 i = 0; i < count; i++)
1469 			delete fStreams[i];
1470 		delete[] fStreams;
1471 	}
1472 }
1473 
1474 
1475 // #pragma mark -
1476 
1477 
1478 const char*
1479 AVFormatReader::Copyright()
1480 {
1481 // TODO: Could not find the equivalent in libavformat >= version 53.
1482 // Use metadata API instead!
1483 //	if (fStreams != NULL && fStreams[0] != NULL)
1484 //		return fStreams[0]->Context()->copyright;
1485 	// TODO: Return copyright of the file instead!
1486 	return "Copyright 2009, Stephan Aßmus";
1487 }
1488 
1489 
1490 status_t
1491 AVFormatReader::Sniff(int32* _streamCount)
1492 {
1493 	TRACE("AVFormatReader::Sniff\n");
1494 
1495 	BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1496 	if (source == NULL) {
1497 		TRACE("  not a BPositionIO, but we need it to be one.\n");
1498 		return B_NOT_SUPPORTED;
1499 	}
1500 
1501 	Stream* stream = new(std::nothrow) Stream(source,
1502 		&fSourceLock);
1503 	if (stream == NULL) {
1504 		ERROR("AVFormatReader::Sniff() - failed to allocate Stream\n");
1505 		return B_NO_MEMORY;
1506 	}
1507 
1508 	ObjectDeleter<Stream> streamDeleter(stream);
1509 
1510 	status_t ret = stream->Open();
1511 	if (ret != B_OK) {
1512 		TRACE("  failed to detect stream: %s\n", strerror(ret));
1513 		return ret;
1514 	}
1515 
1516 	delete[] fStreams;
1517 	fStreams = NULL;
1518 
1519 	int32 streamCount = stream->CountStreams();
1520 	if (streamCount == 0) {
1521 		TRACE("  failed to detect any streams: %s\n", strerror(ret));
1522 		return B_ERROR;
1523 	}
1524 
1525 	fStreams = new(std::nothrow) Stream*[streamCount];
1526 	if (fStreams == NULL) {
1527 		ERROR("AVFormatReader::Sniff() - failed to allocate streams\n");
1528 		return B_NO_MEMORY;
1529 	}
1530 
1531 	memset(fStreams, 0, sizeof(Stream*) * streamCount);
1532 	fStreams[0] = stream;
1533 	streamDeleter.Detach();
1534 
1535 	#ifdef TRACE_AVFORMAT_READER
1536 	dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0);
1537 	#endif
1538 
1539 	if (_streamCount != NULL)
1540 		*_streamCount = streamCount;
1541 
1542 	return B_OK;
1543 }
1544 
1545 
1546 void
1547 AVFormatReader::GetFileFormatInfo(media_file_format* mff)
1548 {
1549 	TRACE("AVFormatReader::GetFileFormatInfo\n");
1550 
1551 	if (fStreams == NULL)
1552 		return;
1553 
1554 	// The first cookie is always there!
1555 	const AVFormatContext* context = fStreams[0]->Context();
1556 
1557 	if (context == NULL || context->iformat == NULL) {
1558 		TRACE("  no AVFormatContext or AVInputFormat!\n");
1559 		return;
1560 	}
1561 
1562 	const DemuxerFormat* format = demuxer_format_for(context->iformat);
1563 
1564 	mff->capabilities = media_file_format::B_READABLE
1565 		| media_file_format::B_KNOWS_ENCODED_VIDEO
1566 		| media_file_format::B_KNOWS_ENCODED_AUDIO
1567 		| media_file_format::B_IMPERFECTLY_SEEKABLE;
1568 
1569 	if (format != NULL) {
1570 		// TODO: Check if AVInputFormat has audio only and then use
1571 		// format->audio_family!
1572 		mff->family = format->video_family;
1573 	} else {
1574 		TRACE("  no DemuxerFormat for AVInputFormat!\n");
1575 		mff->family = B_MISC_FORMAT_FAMILY;
1576 	}
1577 
1578 	mff->version = 100;
1579 
1580 	if (format != NULL) {
1581 		strcpy(mff->mime_type, format->mime_type);
1582 	} else {
1583 		// TODO: Would be nice to be able to provide this from AVInputFormat,
1584 		// maybe by extending the FFmpeg code itself (all demuxers).
1585 		strcpy(mff->mime_type, "");
1586 	}
1587 
1588 	if (context->iformat->extensions != NULL)
1589 		strcpy(mff->file_extension, context->iformat->extensions);
1590 	else {
1591 		TRACE("  no file extensions for AVInputFormat.\n");
1592 		strcpy(mff->file_extension, "");
1593 	}
1594 
1595 	if (context->iformat->name != NULL)
1596 		strcpy(mff->short_name,  context->iformat->name);
1597 	else {
1598 		TRACE("  no short name for AVInputFormat.\n");
1599 		strcpy(mff->short_name, "");
1600 	}
1601 
1602 	if (context->iformat->long_name != NULL)
1603 		sprintf(mff->pretty_name, "%s (FFmpeg)", context->iformat->long_name);
1604 	else {
1605 		if (format != NULL)
1606 			sprintf(mff->pretty_name, "%s (FFmpeg)", format->pretty_name);
1607 		else
1608 			strcpy(mff->pretty_name, "Unknown (FFmpeg)");
1609 	}
1610 }
1611 
1612 
1613 status_t
1614 AVFormatReader::GetMetaData(BMessage* _data)
1615 {
1616 	// The first cookie is always there!
1617 	const AVFormatContext* context = fStreams[0]->Context();
1618 
1619 	if (context == NULL)
1620 		return B_NO_INIT;
1621 
1622 	avdictionary_to_message(context->metadata, _data);
1623 
1624 	// Add chapter info
1625 	for (unsigned i = 0; i < context->nb_chapters; i++) {
1626 		AVChapter* chapter = context->chapters[i];
1627 		BMessage chapterData;
1628 		chapterData.AddInt64("start", bigtime_t(1000000.0
1629 			* chapter->start * chapter->time_base.num
1630 			/ chapter->time_base.den + 0.5));
1631 		chapterData.AddInt64("end", bigtime_t(1000000.0
1632 			* chapter->end * chapter->time_base.num
1633 			/ chapter->time_base.den + 0.5));
1634 
1635 		avdictionary_to_message(chapter->metadata, &chapterData);
1636 		_data->AddMessage("be:chapter", &chapterData);
1637 	}
1638 
1639 	// Add program info
1640 	for (unsigned i = 0; i < context->nb_programs; i++) {
1641 		BMessage progamData;
1642 		avdictionary_to_message(context->programs[i]->metadata, &progamData);
1643 		_data->AddMessage("be:program", &progamData);
1644 	}
1645 
1646 	return B_OK;
1647 }
1648 
1649 
1650 // #pragma mark -
1651 
1652 
1653 status_t
1654 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie)
1655 {
1656 	TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex);
1657 
1658 	BAutolock _(fSourceLock);
1659 
1660 	if (fStreams == NULL)
1661 		return B_NO_INIT;
1662 
1663 	if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams())
1664 		return B_BAD_INDEX;
1665 
1666 	if (_cookie == NULL)
1667 		return B_BAD_VALUE;
1668 
1669 	Stream* cookie = fStreams[streamIndex];
1670 	if (cookie == NULL) {
1671 		// Allocate the cookie
1672 		BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
1673 		if (source == NULL) {
1674 			TRACE("  not a BPositionIO, but we need it to be one.\n");
1675 			return B_NOT_SUPPORTED;
1676 		}
1677 
1678 		cookie = new(std::nothrow) Stream(source, &fSourceLock);
1679 		if (cookie == NULL) {
1680 			ERROR("AVFormatReader::Sniff() - failed to allocate "
1681 				"Stream\n");
1682 			return B_NO_MEMORY;
1683 		}
1684 
1685 		status_t ret = cookie->Open();
1686 		if (ret != B_OK) {
1687 			TRACE("  stream failed to open: %s\n", strerror(ret));
1688 			delete cookie;
1689 			return ret;
1690 		}
1691 	}
1692 
1693 	status_t ret = cookie->Init(streamIndex);
1694 	if (ret != B_OK) {
1695 		TRACE("  stream failed to initialize: %s\n", strerror(ret));
1696 		// NOTE: Never delete the first stream!
1697 		if (streamIndex != 0)
1698 			delete cookie;
1699 		return ret;
1700 	}
1701 
1702 	fStreams[streamIndex] = cookie;
1703 	*_cookie = cookie;
1704 
1705 	return B_OK;
1706 }
1707 
1708 
1709 status_t
1710 AVFormatReader::FreeCookie(void *_cookie)
1711 {
1712 	BAutolock _(fSourceLock);
1713 
1714 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1715 
1716 	// NOTE: Never delete the first cookie!
1717 	if (cookie != NULL && cookie->VirtualIndex() != 0) {
1718 		if (fStreams != NULL)
1719 			fStreams[cookie->VirtualIndex()] = NULL;
1720 		delete cookie;
1721 	}
1722 
1723 	return B_OK;
1724 }
1725 
1726 
1727 // #pragma mark -
1728 
1729 
1730 status_t
1731 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
1732 	bigtime_t* duration, media_format* format, const void** infoBuffer,
1733 	size_t* infoSize)
1734 {
1735 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1736 	return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer,
1737 		infoSize);
1738 }
1739 
1740 
1741 status_t
1742 AVFormatReader::GetStreamMetaData(void* _cookie, BMessage* _data)
1743 {
1744 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1745 	return cookie->GetMetaData(_data);
1746 }
1747 
1748 
1749 status_t
1750 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame,
1751 	bigtime_t* time)
1752 {
1753 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1754 	return cookie->Seek(seekTo, frame, time);
1755 }
1756 
1757 
1758 status_t
1759 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame,
1760 	bigtime_t* time)
1761 {
1762 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1763 	return cookie->FindKeyFrame(flags, frame, time);
1764 }
1765 
1766 
1767 status_t
1768 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer,
1769 	size_t* chunkSize, media_header* mediaHeader)
1770 {
1771 	Stream* cookie = reinterpret_cast<Stream*>(_cookie);
1772 	return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
1773 }
1774 
1775 
1776