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