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