1/*
2 * Copyright (C) 2001 Carlos Hasan
3 * Copyright (C) 2001 Fran��ois Revol
4 * Copyright (C) 2001 Axel D��rfler
5 * Copyright (C) 2004 Marcus Overhagen
6 * Copyright (C) 2009 Stephan Am��us <superstippi@gmx.de>
7 *
8 * All rights reserved. Distributed under the terms of the MIT License.
9 */
10
11//! libavcodec based decoder for Haiku
12
13#include "AVCodecDecoder.h"
14
15#include <new>
16
17#include <string.h>
18
19#include <Bitmap.h>
20#include <Debug.h>
21
22
23#undef TRACE
24//#define TRACE_AV_CODEC
25#ifdef TRACE_AV_CODEC
26#	define TRACE(x...)	printf(x)
27#	define TRACE_AUDIO(x...)	printf(x)
28#	define TRACE_VIDEO(x...)	printf(x)
29#else
30#	define TRACE(x...)
31#	define TRACE_AUDIO(x...)
32#	define TRACE_VIDEO(x...)
33#endif
34
35//#define LOG_STREAM_TO_FILE
36#ifdef LOG_STREAM_TO_FILE
37#	include <File.h>
38	static BFile sStreamLogFile("/boot/home/Desktop/AVCodecDebugStream.raw",
39		B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
40	static int sDumpedPackets = 0;
41#endif
42
43#define USE_SWS_FOR_COLOR_SPACE_CONVERSION 0
44// NOTE: David's color space conversion is much faster than the FFmpeg
45// version. Perhaps the SWS code can be used for unsupported conversions?
46// Otherwise the alternative code could simply be removed from this file.
47
48
49struct wave_format_ex {
50	uint16 format_tag;
51	uint16 channels;
52	uint32 frames_per_sec;
53	uint32 avg_bytes_per_sec;
54	uint16 block_align;
55	uint16 bits_per_sample;
56	uint16 extra_size;
57	// extra_data[extra_size]
58} _PACKED;
59
60
61// profiling related globals
62#define DO_PROFILING 0
63
64static bigtime_t decodingTime = 0;
65static bigtime_t conversionTime = 0;
66static long profileCounter = 0;
67
68
69AVCodecDecoder::AVCodecDecoder()
70	:
71	fHeader(),
72	fInputFormat(),
73	fOutputVideoFormat(),
74	fFrame(0),
75	fIsAudio(false),
76	fCodec(NULL),
77	fContext(avcodec_alloc_context3(NULL)),
78	fInputPicture(avcodec_alloc_frame()),
79	fOutputPicture(avcodec_alloc_frame()),
80
81	fCodecInitDone(false),
82
83#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
84	fSwsContext(NULL),
85#else
86	fFormatConversionFunc(NULL),
87#endif
88
89	fExtraData(NULL),
90	fExtraDataSize(0),
91	fBlockAlign(0),
92
93	fStartTime(0),
94	fOutputFrameCount(0),
95	fOutputFrameRate(1.0),
96	fOutputFrameSize(0),
97
98	fChunkBuffer(NULL),
99	fChunkBufferOffset(0),
100	fChunkBufferSize(0),
101	fAudioDecodeError(false),
102
103	fOutputFrame(avcodec_alloc_frame()),
104	fOutputBufferOffset(0),
105	fOutputBufferSize(0)
106{
107	TRACE("AVCodecDecoder::AVCodecDecoder()\n");
108
109	system_info info;
110	get_system_info(&info);
111
112	fContext->err_recognition = AV_EF_CAREFUL;
113	fContext->error_concealment = 3;
114	fContext->thread_count = info.cpu_count;
115}
116
117
118AVCodecDecoder::~AVCodecDecoder()
119{
120	TRACE("[%c] AVCodecDecoder::~AVCodecDecoder()\n", fIsAudio?('a'):('v'));
121
122#ifdef DO_PROFILING
123	if (profileCounter > 0) {
124		printf("[%c] profile: d1 = %lld, d2 = %lld (%Ld)\n",
125			fIsAudio?('a'):('v'), decodingTime / profileCounter,
126			conversionTime / profileCounter, fFrame);
127	}
128#endif
129
130	if (fCodecInitDone)
131		avcodec_close(fContext);
132
133	av_free(fOutputPicture);
134	av_free(fInputPicture);
135	av_free(fContext);
136	av_free(fOutputFrame);
137
138#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
139	if (fSwsContext != NULL)
140		sws_freeContext(fSwsContext);
141#endif
142
143	delete[] fExtraData;
144}
145
146
147void
148AVCodecDecoder::GetCodecInfo(media_codec_info* mci)
149{
150	snprintf(mci->short_name, 32, "%s", fCodec->name);
151	snprintf(mci->pretty_name, 96, "%s", fCodec->long_name);
152	mci->id = 0;
153	mci->sub_id = fCodec->id;
154}
155
156
157status_t
158AVCodecDecoder::Setup(media_format* ioEncodedFormat, const void* infoBuffer,
159	size_t infoSize)
160{
161	if (ioEncodedFormat->type != B_MEDIA_ENCODED_AUDIO
162		&& ioEncodedFormat->type != B_MEDIA_ENCODED_VIDEO)
163		return B_ERROR;
164
165	fIsAudio = (ioEncodedFormat->type == B_MEDIA_ENCODED_AUDIO);
166	TRACE("[%c] AVCodecDecoder::Setup()\n", fIsAudio?('a'):('v'));
167
168#ifdef TRACE_AV_CODEC
169	char buffer[1024];
170	string_for_format(*ioEncodedFormat, buffer, sizeof(buffer));
171	TRACE("[%c]   input_format = %s\n", fIsAudio?('a'):('v'), buffer);
172	TRACE("[%c]   infoSize = %ld\n", fIsAudio?('a'):('v'), infoSize);
173	TRACE("[%c]   user_data_type = %08lx\n", fIsAudio?('a'):('v'),
174		ioEncodedFormat->user_data_type);
175	TRACE("[%c]   meta_data_size = %ld\n", fIsAudio?('a'):('v'),
176		ioEncodedFormat->MetaDataSize());
177#endif
178
179	media_format_description description;
180	if (BMediaFormats().GetCodeFor(*ioEncodedFormat,
181			B_MISC_FORMAT_FAMILY, &description) == B_OK) {
182		if (description.u.misc.file_format != 'ffmp')
183			return B_NOT_SUPPORTED;
184		fCodec = avcodec_find_decoder(static_cast<CodecID>(
185			description.u.misc.codec));
186		if (fCodec == NULL) {
187			TRACE("  unable to find the correct FFmpeg "
188				"decoder (id = %lu)\n", description.u.misc.codec);
189			return B_ERROR;
190		}
191		TRACE("  found decoder %s\n", fCodec->name);
192
193		const void* extraData = infoBuffer;
194		fExtraDataSize = infoSize;
195		if (description.family == B_WAV_FORMAT_FAMILY
196				&& infoSize >= sizeof(wave_format_ex)) {
197			TRACE("  trying to use wave_format_ex\n");
198			// Special case extra data in B_WAV_FORMAT_FAMILY
199			const wave_format_ex* waveFormatData
200				= (const wave_format_ex*)infoBuffer;
201
202			size_t waveFormatSize = infoSize;
203			if (waveFormatData != NULL && waveFormatSize > 0) {
204				fBlockAlign = waveFormatData->block_align;
205				TRACE("  found block align: %d\n", fBlockAlign);
206				fExtraDataSize = waveFormatData->extra_size;
207				// skip the wave_format_ex from the extra data.
208				extraData = waveFormatData + 1;
209			}
210		} else {
211			if (fIsAudio) {
212				fBlockAlign
213					= ioEncodedFormat->u.encoded_audio.output
214						.buffer_size;
215				TRACE("  using buffer_size as block align: %d\n",
216					fBlockAlign);
217			}
218		}
219		if (extraData != NULL && fExtraDataSize > 0) {
220			TRACE("AVCodecDecoder: extra data size %ld\n", infoSize);
221			delete[] fExtraData;
222			fExtraData = new(std::nothrow) char[fExtraDataSize];
223			if (fExtraData != NULL)
224				memcpy(fExtraData, infoBuffer, fExtraDataSize);
225			else
226				fExtraDataSize = 0;
227		}
228
229		fInputFormat = *ioEncodedFormat;
230		return B_OK;
231	} else {
232		TRACE("AVCodecDecoder: BMediaFormats().GetCodeFor() failed.\n");
233	}
234
235	printf("AVCodecDecoder::Setup failed!\n");
236	return B_ERROR;
237}
238
239
240status_t
241AVCodecDecoder::SeekedTo(int64 frame, bigtime_t time)
242{
243	status_t ret = B_OK;
244	// Reset the FFmpeg codec to flush buffers, so we keep the sync
245	if (fCodecInitDone)
246		avcodec_flush_buffers(fContext);
247
248	// Flush internal buffers as well.
249	fChunkBuffer = NULL;
250	fChunkBufferOffset = 0;
251	fChunkBufferSize = 0;
252	fOutputBufferOffset = 0;
253	fOutputBufferSize = 0;
254
255	fFrame = frame;
256	fStartTime = time;
257
258	return ret;
259}
260
261
262status_t
263AVCodecDecoder::NegotiateOutputFormat(media_format* inOutFormat)
264{
265	TRACE("AVCodecDecoder::NegotiateOutputFormat() [%c] \n",
266		fIsAudio?('a'):('v'));
267
268#ifdef TRACE_AV_CODEC
269	char buffer[1024];
270	string_for_format(*inOutFormat, buffer, sizeof(buffer));
271	TRACE("  [%c]  requested format = %s\n", fIsAudio?('a'):('v'), buffer);
272#endif
273
274	if (fIsAudio)
275		return _NegotiateAudioOutputFormat(inOutFormat);
276	else
277		return _NegotiateVideoOutputFormat(inOutFormat);
278}
279
280
281status_t
282AVCodecDecoder::Decode(void* outBuffer, int64* outFrameCount,
283	media_header* mediaHeader, media_decode_info* info)
284{
285	if (!fCodecInitDone)
286		return B_NO_INIT;
287
288//	TRACE("[%c] AVCodecDecoder::Decode() for time %Ld\n", fIsAudio?('a'):('v'),
289//		fStartTime);
290
291	mediaHeader->start_time = fStartTime;
292
293	status_t ret;
294	if (fIsAudio)
295		ret = _DecodeAudio(outBuffer, outFrameCount, mediaHeader, info);
296	else
297		ret = _DecodeVideo(outBuffer, outFrameCount, mediaHeader, info);
298
299	return ret;
300}
301
302
303// #pragma mark -
304
305
306status_t
307AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat)
308{
309	TRACE("AVCodecDecoder::_NegotiateAudioOutputFormat()\n");
310
311	media_multi_audio_format outputAudioFormat;
312	outputAudioFormat = media_raw_audio_format::wildcard;
313	outputAudioFormat.byte_order = B_MEDIA_HOST_ENDIAN;
314	outputAudioFormat.frame_rate
315		= fInputFormat.u.encoded_audio.output.frame_rate;
316	outputAudioFormat.channel_count
317		= fInputFormat.u.encoded_audio.output.channel_count;
318	outputAudioFormat.format = fInputFormat.u.encoded_audio.output.format;
319	outputAudioFormat.buffer_size
320		= inOutFormat->u.raw_audio.buffer_size;
321	// Check that format is not still a wild card!
322	if (outputAudioFormat.format == 0) {
323		TRACE("  format still a wild-card, assuming B_AUDIO_SHORT.\n");
324		outputAudioFormat.format = media_raw_audio_format::B_AUDIO_SHORT;
325	}
326	size_t sampleSize = outputAudioFormat.format
327		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
328	// Check that channel count is not still a wild card!
329	if (outputAudioFormat.channel_count == 0) {
330		TRACE("  channel_count still a wild-card, assuming stereo.\n");
331		outputAudioFormat.channel_count = 2;
332	}
333
334	if (outputAudioFormat.buffer_size == 0) {
335		outputAudioFormat.buffer_size = 512
336			* sampleSize * outputAudioFormat.channel_count;
337	}
338	inOutFormat->type = B_MEDIA_RAW_AUDIO;
339	inOutFormat->u.raw_audio = outputAudioFormat;
340
341	fContext->bit_rate = (int)fInputFormat.u.encoded_audio.bit_rate;
342	fContext->frame_size = (int)fInputFormat.u.encoded_audio.frame_size;
343	fContext->sample_rate
344		= (int)fInputFormat.u.encoded_audio.output.frame_rate;
345	fContext->channels = outputAudioFormat.channel_count;
346	fContext->block_align = fBlockAlign;
347	fContext->extradata = (uint8_t*)fExtraData;
348	fContext->extradata_size = fExtraDataSize;
349
350	// TODO: This probably needs to go away, there is some misconception
351	// about extra data / info buffer and meta data. See
352	// Reader::GetStreamInfo(). The AVFormatReader puts extradata and
353	// extradata_size into media_format::MetaData(), but used to ignore
354	// the infoBuffer passed to GetStreamInfo(). I think this may be why
355	// the code below was added.
356	if (fInputFormat.MetaDataSize() > 0) {
357		fContext->extradata = (uint8_t*)fInputFormat.MetaData();
358		fContext->extradata_size = fInputFormat.MetaDataSize();
359	}
360
361	TRACE("  bit_rate %d, sample_rate %d, channels %d, block_align %d, "
362		"extradata_size %d\n", fContext->bit_rate, fContext->sample_rate,
363		fContext->channels, fContext->block_align, fContext->extradata_size);
364
365	// close any previous instance
366	if (fCodecInitDone) {
367		fCodecInitDone = false;
368		avcodec_close(fContext);
369	}
370
371	// open new
372	int result = avcodec_open2(fContext, fCodec, NULL);
373	fCodecInitDone = (result >= 0);
374
375	fStartTime = 0;
376	fOutputFrameSize = sampleSize * outputAudioFormat.channel_count;
377	fOutputFrameCount = outputAudioFormat.buffer_size / fOutputFrameSize;
378	fOutputFrameRate = outputAudioFormat.frame_rate;
379
380	TRACE("  bit_rate = %d, sample_rate = %d, channels = %d, init = %d, "
381		"output frame size: %d, count: %ld, rate: %.2f\n",
382		fContext->bit_rate, fContext->sample_rate, fContext->channels,
383		result, fOutputFrameSize, fOutputFrameCount, fOutputFrameRate);
384
385	fChunkBuffer = NULL;
386	fChunkBufferOffset = 0;
387	fChunkBufferSize = 0;
388	fAudioDecodeError = false;
389	fOutputBufferOffset = 0;
390	fOutputBufferSize = 0;
391
392	av_init_packet(&fTempPacket);
393
394	inOutFormat->require_flags = 0;
395	inOutFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
396
397	if (!fCodecInitDone) {
398		TRACE("avcodec_open() failed!\n");
399		return B_ERROR;
400	}
401
402	return B_OK;
403}
404
405
406status_t
407AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat)
408{
409	TRACE("AVCodecDecoder::_NegotiateVideoOutputFormat()\n");
410
411	fOutputVideoFormat = fInputFormat.u.encoded_video.output;
412
413	fContext->width = fOutputVideoFormat.display.line_width;
414	fContext->height = fOutputVideoFormat.display.line_count;
415//	fContext->frame_rate = (int)(fOutputVideoFormat.field_rate
416//		* fContext->frame_rate_base);
417
418	fOutputFrameRate = fOutputVideoFormat.field_rate;
419
420	fContext->extradata = (uint8_t*)fExtraData;
421	fContext->extradata_size = fExtraDataSize;
422
423	TRACE("  requested video format 0x%x\n",
424		inOutFormat->u.raw_video.display.format);
425
426	// Make MediaPlayer happy (if not in rgb32 screen depth and no overlay,
427	// it will only ask for YCbCr, which DrawBitmap doesn't handle, so the
428	// default colordepth is RGB32).
429	if (inOutFormat->u.raw_video.display.format == B_YCbCr422)
430		fOutputVideoFormat.display.format = B_YCbCr422;
431	else
432		fOutputVideoFormat.display.format = B_RGB32;
433
434	// Search for a pixel-format the codec handles
435	// TODO: We should try this a couple of times until it succeeds, each
436	// time using another pixel-format that is supported by the decoder.
437	// But libavcodec doesn't seem to offer any way to tell the decoder
438	// which format it should use.
439#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
440	if (fSwsContext != NULL)
441		sws_freeContext(fSwsContext);
442	fSwsContext = NULL;
443#else
444	fFormatConversionFunc = 0;
445#endif
446	// Iterate over supported codec formats
447	for (int i = 0; i < 1; i++) {
448		// close any previous instance
449		if (fCodecInitDone) {
450			fCodecInitDone = false;
451			avcodec_close(fContext);
452		}
453		// TODO: Set n-th fContext->pix_fmt here
454		if (avcodec_open2(fContext, fCodec, NULL) >= 0) {
455			fCodecInitDone = true;
456
457#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
458			fSwsContext = sws_getContext(fContext->width, fContext->height,
459				fContext->pix_fmt, fContext->width, fContext->height,
460				colorspace_to_pixfmt(fOutputVideoFormat.display.format),
461				SWS_FAST_BILINEAR, NULL, NULL, NULL);
462		}
463#else
464			fFormatConversionFunc = resolve_colorspace(
465				fOutputVideoFormat.display.format, fContext->pix_fmt,
466				fContext->width, fContext->height);
467		}
468		if (fFormatConversionFunc != NULL)
469			break;
470#endif
471	}
472
473	if (!fCodecInitDone) {
474		TRACE("avcodec_open() failed to init codec!\n");
475		return B_ERROR;
476	}
477
478#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
479	if (fSwsContext == NULL) {
480		TRACE("No SWS Scale context or decoder has not set the pixel format "
481			"yet!\n");
482	}
483#else
484	if (fFormatConversionFunc == NULL) {
485		TRACE("no pixel format conversion function found or decoder has "
486			"not set the pixel format yet!\n");
487	}
488#endif
489
490	if (fOutputVideoFormat.display.format == B_YCbCr422) {
491		fOutputVideoFormat.display.bytes_per_row
492			= 2 * fOutputVideoFormat.display.line_width;
493	} else {
494		fOutputVideoFormat.display.bytes_per_row
495			= 4 * fOutputVideoFormat.display.line_width;
496	}
497
498	inOutFormat->type = B_MEDIA_RAW_VIDEO;
499	inOutFormat->u.raw_video = fOutputVideoFormat;
500
501	inOutFormat->require_flags = 0;
502	inOutFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
503
504#ifdef TRACE_AV_CODEC
505	char buffer[1024];
506	string_for_format(*inOutFormat, buffer, sizeof(buffer));
507	TRACE("[v]  outFormat = %s\n", buffer);
508	TRACE("  returned  video format 0x%x\n",
509		inOutFormat->u.raw_video.display.format);
510#endif
511
512	return B_OK;
513}
514
515
516status_t
517AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount,
518	media_header* mediaHeader, media_decode_info* info)
519{
520	TRACE_AUDIO("AVCodecDecoder::_DecodeAudio(audio start_time %.6fs)\n",
521		mediaHeader->start_time / 1000000.0);
522
523	*outFrameCount = 0;
524
525	uint8* buffer = reinterpret_cast<uint8*>(_buffer);
526	while (*outFrameCount < fOutputFrameCount) {
527		// Check conditions which would hint at broken code below.
528		if (fOutputBufferSize < 0) {
529			fprintf(stderr, "Decoding read past the end of the output buffer! "
530				"%ld\n", fOutputBufferSize);
531			fOutputBufferSize = 0;
532		}
533		if (fChunkBufferSize < 0) {
534			fprintf(stderr, "Decoding read past the end of the chunk buffer! "
535				"%ld\n", fChunkBufferSize);
536			fChunkBufferSize = 0;
537		}
538
539		if (fOutputBufferSize > 0) {
540			// We still have decoded audio frames from the last
541			// invokation, which start at fOutputBufferOffset
542			// and are of fOutputBufferSize. Copy those into the buffer,
543			// but not more than it can hold.
544			int32 frames = min_c(fOutputFrameCount - *outFrameCount,
545				fOutputBufferSize / fOutputFrameSize);
546			if (frames == 0)
547				debugger("fOutputBufferSize not multiple of frame size!");
548			size_t remainingSize = frames * fOutputFrameSize;
549			memcpy(buffer, fOutputFrame->data[0] + fOutputBufferOffset,
550				remainingSize);
551			fOutputBufferOffset += remainingSize;
552			fOutputBufferSize -= remainingSize;
553			buffer += remainingSize;
554			*outFrameCount += frames;
555			fStartTime += (bigtime_t)((1000000LL * frames) / fOutputFrameRate);
556			continue;
557		}
558		if (fChunkBufferSize == 0) {
559			// Time to read the next chunk buffer. We use a separate
560			// media_header, since the chunk header may not belong to
561			// the start of the decoded audio frames we return. For
562			// example we may have used frames from a previous invokation,
563			// or we may have to read several chunks until we fill up the
564			// output buffer.
565			media_header chunkMediaHeader;
566			status_t err = GetNextChunk(&fChunkBuffer, &fChunkBufferSize,
567				&chunkMediaHeader);
568			if (err == B_LAST_BUFFER_ERROR) {
569				TRACE_AUDIO("  Last Chunk with chunk size %ld\n",
570					fChunkBufferSize);
571				fChunkBufferSize = 0;
572				return err;
573			}
574			if (err != B_OK || fChunkBufferSize < 0) {
575				printf("GetNextChunk error %ld\n",fChunkBufferSize);
576				fChunkBufferSize = 0;
577				break;
578			}
579			fChunkBufferOffset = 0;
580			fStartTime = chunkMediaHeader.start_time;
581		}
582
583		fTempPacket.data = (uint8_t*)fChunkBuffer + fChunkBufferOffset;
584		fTempPacket.size = fChunkBufferSize;
585
586		avcodec_get_frame_defaults(fOutputFrame);
587		int gotFrame = 0;
588		int usedBytes = avcodec_decode_audio4(fContext,
589			fOutputFrame, &gotFrame, &fTempPacket);
590		if (usedBytes < 0 && !fAudioDecodeError) {
591			// Report failure if not done already
592			printf("########### audio decode error, "
593				"fChunkBufferSize %ld, fChunkBufferOffset %ld\n",
594				fChunkBufferSize, fChunkBufferOffset);
595			fAudioDecodeError = true;
596		}
597		if (usedBytes <= 0) {
598			// Error or failure to produce decompressed output.
599			// Skip the chunk buffer data entirely.
600			usedBytes = fChunkBufferSize;
601			fOutputBufferSize = 0;
602			// Assume the audio decoded until now is broken.
603			memset(_buffer, 0, buffer - (uint8*)_buffer);
604		} else {
605			// Success
606			fAudioDecodeError = false;
607			if (gotFrame == 1) {
608				fOutputBufferSize = av_samples_get_buffer_size(NULL,
609					fContext->channels, fOutputFrame->nb_samples,
610					fContext->sample_fmt, 1);
611				if (fOutputBufferSize < 0)
612					fOutputBufferSize = 0;
613			} else
614				fOutputBufferSize = 0;
615		}
616//printf("  chunk size: %d, decoded: %d, used: %d\n",
617//fTempPacket.size, decodedBytes, usedBytes);
618
619		fChunkBufferOffset += usedBytes;
620		fChunkBufferSize -= usedBytes;
621		fOutputBufferOffset = 0;
622	}
623	fFrame += *outFrameCount;
624	TRACE_AUDIO("  frame count: %lld current: %lld\n", *outFrameCount, fFrame);
625
626	return B_OK;
627}
628
629
630status_t
631AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
632	media_header* mediaHeader, media_decode_info* info)
633{
634	bool firstRun = true;
635	while (true) {
636		const void* data;
637		size_t size;
638		media_header chunkMediaHeader;
639		status_t err = GetNextChunk(&data, &size, &chunkMediaHeader);
640		if (err != B_OK) {
641			TRACE("AVCodecDecoder::_DecodeVideo(): error from "
642				"GetNextChunk(): %s\n", strerror(err));
643			return err;
644		}
645#ifdef LOG_STREAM_TO_FILE
646		if (sDumpedPackets < 100) {
647			sStreamLogFile.Write(data, size);
648			printf("wrote %ld bytes\n", size);
649			sDumpedPackets++;
650		} else if (sDumpedPackets == 100)
651			sStreamLogFile.Unset();
652#endif
653
654		if (firstRun) {
655			firstRun = false;
656
657			mediaHeader->type = B_MEDIA_RAW_VIDEO;
658			mediaHeader->start_time = chunkMediaHeader.start_time;
659			fStartTime = chunkMediaHeader.start_time;
660			mediaHeader->file_pos = 0;
661			mediaHeader->orig_size = 0;
662			mediaHeader->u.raw_video.field_gamma = 1.0;
663			mediaHeader->u.raw_video.field_sequence = fFrame;
664			mediaHeader->u.raw_video.field_number = 0;
665			mediaHeader->u.raw_video.pulldown_number = 0;
666			mediaHeader->u.raw_video.first_active_line = 1;
667			mediaHeader->u.raw_video.line_count
668				= fOutputVideoFormat.display.line_count;
669
670			TRACE("[v] start_time=%02d:%02d.%02d field_sequence=%lu\n",
671				int((mediaHeader->start_time / 60000000) % 60),
672				int((mediaHeader->start_time / 1000000) % 60),
673				int((mediaHeader->start_time / 10000) % 100),
674				mediaHeader->u.raw_video.field_sequence);
675		}
676
677#if DO_PROFILING
678		bigtime_t startTime = system_time();
679#endif
680
681		// NOTE: In the FFmpeg code example I've read, the length returned by
682		// avcodec_decode_video() is completely ignored. Furthermore, the
683		// packet buffers are supposed to contain complete frames only so we
684		// don't seem to be required to buffer any packets because not the
685		// complete packet has been read.
686		fTempPacket.data = (uint8_t*)data;
687		fTempPacket.size = size;
688		int gotPicture = 0;
689		int len = avcodec_decode_video2(fContext, fInputPicture, &gotPicture,
690			&fTempPacket);
691		if (len < 0) {
692			TRACE("[v] AVCodecDecoder: error in decoding frame %lld: %d\n",
693				fFrame, len);
694			// NOTE: An error from avcodec_decode_video() seems to be ignored
695			// in the ffplay sample code.
696//			return B_ERROR;
697		}
698
699
700//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
701//	"fContext->frame_rate = %ld\n", (int)(fContext->pts / (60*60*1000000)),
702//	(int)(fContext->pts / (60*1000000)), (int)(fContext->pts / (1000000)),
703//	(int)(fContext->pts % 1000000), fContext->frame_number,
704//	fContext->frame_rate);
705//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
706//	"fContext->frame_rate = %ld\n",
707//	(int)(fInputPicture->pts / (60*60*1000000)),
708//	(int)(fInputPicture->pts / (60*1000000)),
709//	(int)(fInputPicture->pts / (1000000)),
710//	(int)(fInputPicture->pts % 1000000), fContext->frame_number,
711//	fContext->frame_rate);
712
713		if (gotPicture) {
714			int width = fOutputVideoFormat.display.line_width;
715			int height = fOutputVideoFormat.display.line_count;
716			AVPicture deinterlacedPicture;
717			bool useDeinterlacedPicture = false;
718
719			if (fInputPicture->interlaced_frame) {
720				AVPicture source;
721				source.data[0] = fInputPicture->data[0];
722				source.data[1] = fInputPicture->data[1];
723				source.data[2] = fInputPicture->data[2];
724				source.data[3] = fInputPicture->data[3];
725				source.linesize[0] = fInputPicture->linesize[0];
726				source.linesize[1] = fInputPicture->linesize[1];
727				source.linesize[2] = fInputPicture->linesize[2];
728				source.linesize[3] = fInputPicture->linesize[3];
729
730				avpicture_alloc(&deinterlacedPicture,
731					fContext->pix_fmt, width, height);
732
733				if (avpicture_deinterlace(&deinterlacedPicture, &source,
734						fContext->pix_fmt, width, height) < 0) {
735					TRACE("[v] avpicture_deinterlace() - error\n");
736				} else
737					useDeinterlacedPicture = true;
738			}
739
740#if DO_PROFILING
741			bigtime_t formatConversionStart = system_time();
742#endif
743//			TRACE("ONE FRAME OUT !! len=%d size=%ld (%s)\n", len, size,
744//				pixfmt_to_string(fContext->pix_fmt));
745
746			// Some decoders do not set pix_fmt until they have decoded 1 frame
747#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
748			if (fSwsContext == NULL) {
749				fSwsContext = sws_getContext(fContext->width, fContext->height,
750					fContext->pix_fmt, fContext->width, fContext->height,
751					colorspace_to_pixfmt(fOutputVideoFormat.display.format),
752					SWS_FAST_BILINEAR, NULL, NULL, NULL);
753			}
754#else
755			if (fFormatConversionFunc == NULL) {
756				fFormatConversionFunc = resolve_colorspace(
757					fOutputVideoFormat.display.format, fContext->pix_fmt,
758					fContext->width, fContext->height);
759			}
760#endif
761
762			fOutputPicture->data[0] = (uint8_t*)outBuffer;
763			fOutputPicture->linesize[0]
764				= fOutputVideoFormat.display.bytes_per_row;
765
766#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
767			if (fSwsContext != NULL) {
768#else
769			if (fFormatConversionFunc != NULL) {
770#endif
771				if (useDeinterlacedPicture) {
772					AVFrame inputFrame;
773					inputFrame.data[0] = deinterlacedPicture.data[0];
774					inputFrame.data[1] = deinterlacedPicture.data[1];
775					inputFrame.data[2] = deinterlacedPicture.data[2];
776					inputFrame.data[3] = deinterlacedPicture.data[3];
777					inputFrame.linesize[0] = deinterlacedPicture.linesize[0];
778					inputFrame.linesize[1] = deinterlacedPicture.linesize[1];
779					inputFrame.linesize[2] = deinterlacedPicture.linesize[2];
780					inputFrame.linesize[3] = deinterlacedPicture.linesize[3];
781
782#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
783					sws_scale(fSwsContext, inputFrame.data,
784						inputFrame.linesize, 0, fContext->height,
785						fOutputPicture->data, fOutputPicture->linesize);
786#else
787					(*fFormatConversionFunc)(&inputFrame,
788						fOutputPicture, width, height);
789#endif
790				} else {
791#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
792					sws_scale(fSwsContext, fInputPicture->data,
793						fInputPicture->linesize, 0, fContext->height,
794						fOutputPicture->data, fOutputPicture->linesize);
795#else
796					(*fFormatConversionFunc)(fInputPicture, fOutputPicture,
797						width, height);
798#endif
799				}
800			}
801			if (fInputPicture->interlaced_frame)
802				avpicture_free(&deinterlacedPicture);
803#ifdef DEBUG
804			dump_ffframe(fInputPicture, "ffpict");
805//			dump_ffframe(fOutputPicture, "opict");
806#endif
807			*outFrameCount = 1;
808			fFrame++;
809
810#if DO_PROFILING
811			bigtime_t doneTime = system_time();
812			decodingTime += formatConversionStart - startTime;
813			conversionTime += doneTime - formatConversionStart;
814			profileCounter++;
815			if (!(fFrame % 5)) {
816				if (info) {
817					printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required "
818						"%Ld\n",
819						decodingTime / profileCounter,
820						conversionTime / profileCounter,
821						fFrame, info->time_to_decode);
822				} else {
823					printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required "
824						"%Ld\n",
825						decodingTime / profileCounter,
826						conversionTime / profileCounter,
827						fFrame, bigtime_t(1000000LL / fOutputFrameRate));
828				}
829				decodingTime = 0;
830				conversionTime = 0;
831				profileCounter = 0;
832			}
833#endif
834			return B_OK;
835		} else {
836			TRACE("frame %lld - no picture yet, len: %d, chunk size: %ld\n",
837				fFrame, len, size);
838		}
839	}
840}
841
842
843