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