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