1/*
2 * Copyright 2009-2010, Stephan Am��us <superstippi@gmx.de>
3 * Copyright 2018, Dario Casalinuovo
4 * All rights reserved. Distributed under the terms of the MIT license.
5 */
6
7
8#include "AVCodecEncoder.h"
9
10#include <new>
11
12#include <stdio.h>
13#include <string.h>
14
15#include <Application.h>
16#include <Roster.h>
17
18extern "C" {
19	#include "rational.h"
20}
21
22#include "EncoderTable.h"
23#include "gfx_util.h"
24
25
26#undef TRACE
27//#define TRACE_AV_CODEC_ENCODER
28#ifdef TRACE_AV_CODEC_ENCODER
29#	define TRACE	printf
30#	define TRACE_IO(a...)
31#else
32#	define TRACE(a...)
33#	define TRACE_IO(a...)
34#endif
35
36
37static const size_t kDefaultChunkBufferSize = 2 * 1024 * 1024;
38
39
40AVCodecEncoder::AVCodecEncoder(uint32 codecID, int bitRateScale)
41	:
42	Encoder(),
43	fBitRateScale(bitRateScale),
44	fCodecID((CodecID)codecID),
45	fCodec(NULL),
46	fCodecContext(NULL),
47	fCodecInitStatus(CODEC_INIT_NEEDED),
48	fFrame(av_frame_alloc()),
49	fSwsContext(NULL),
50	fFramesWritten(0)
51{
52	TRACE("AVCodecEncoder::AVCodecEncoder()\n");
53	_Init();
54}
55
56
57void
58AVCodecEncoder::_Init()
59{
60	fChunkBuffer = new(std::nothrow) uint8[kDefaultChunkBufferSize];
61	if (fCodecID > 0) {
62		fCodec = avcodec_find_encoder(fCodecID);
63		TRACE("  found AVCodec for %u: %p\n", fCodecID, fCodec);
64	}
65
66#if LIBAVCODEC_VERSION_MAJOR >= 60
67	fAudioFifo = av_fifo_alloc2(0, 1, AV_FIFO_FLAG_AUTO_GROW);
68#else
69	fAudioFifo = av_fifo_alloc(0);
70#endif
71
72	// Initial parameters, so we know if the user changed them
73	fEncodeParameters.avg_field_size = 0;
74	fEncodeParameters.max_field_size = 0;
75	fEncodeParameters.quality = 1.0f;
76}
77
78
79AVCodecEncoder::~AVCodecEncoder()
80{
81	TRACE("AVCodecEncoder::~AVCodecEncoder()\n");
82
83	if (fSwsContext != NULL)
84		sws_freeContext(fSwsContext);
85
86#if LIBAVCODEC_VERSION_MAJOR >= 60
87	av_fifo_freep2(&fAudioFifo);
88#else
89	av_fifo_free(fAudioFifo);
90#endif
91
92	if (fFrame != NULL) {
93		av_frame_free(&fFrame);
94	}
95
96	if (fCodecContext != NULL) {
97		avcodec_close(fCodecContext);
98		avcodec_free_context(&fCodecContext);
99	}
100
101	delete[] fChunkBuffer;
102}
103
104
105status_t
106AVCodecEncoder::AcceptedFormat(const media_format* proposedInputFormat,
107	media_format* _acceptedInputFormat)
108{
109	TRACE("AVCodecEncoder::AcceptedFormat(%p, %p)\n", proposedInputFormat,
110		_acceptedInputFormat);
111
112	if (proposedInputFormat == NULL)
113		return B_BAD_VALUE;
114
115	if (_acceptedInputFormat != NULL) {
116		*_acceptedInputFormat = *proposedInputFormat;
117	}
118
119	return B_OK;
120}
121
122
123status_t
124AVCodecEncoder::SetUp(const media_format* inputFormat)
125{
126	TRACE("AVCodecEncoder::SetUp()\n");
127
128	if (inputFormat == NULL)
129		return B_BAD_VALUE;
130
131	// Codec IDs for raw-formats may need to be figured out here.
132	if (fCodec == NULL && fCodecID == AV_CODEC_ID_NONE) {
133		fCodecID = raw_audio_codec_id_for(*inputFormat);
134		if (fCodecID != AV_CODEC_ID_NONE)
135			fCodec = avcodec_find_encoder(fCodecID);
136	}
137	if (fCodec == NULL) {
138		TRACE("  encoder not found!\n");
139		return B_NO_INIT;
140	}
141
142	fInputFormat = *inputFormat;
143	fFramesWritten = 0;
144
145	return _Setup();
146}
147
148
149status_t
150AVCodecEncoder::GetEncodeParameters(encode_parameters* parameters) const
151{
152	TRACE("AVCodecEncoder::GetEncodeParameters(%p)\n", parameters);
153
154// TODO: Implement maintaining an automatically calculated bit_rate versus
155// a user specified (via SetEncodeParameters()) bit_rate. At this point, the
156// fCodecContext->bit_rate may not yet have been specified (_Setup() was never
157// called yet). So it cannot work like the code below, but in any case, it's
158// showing how to convert between the values (albeit untested).
159//	int avgBytesPerSecond = fCodecContext->bit_rate / 8;
160//	int maxBytesPerSecond = (fCodecContext->bit_rate
161//		+ fCodecContext->bit_rate_tolerance) / 8;
162//
163//	if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
164//		fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond
165//			/ fInputFormat.u.raw_audio.frame_rate);
166//		fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond
167//			/ fInputFormat.u.raw_audio.frame_rate);
168//	} else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
169//		fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond
170//			/ fInputFormat.u.raw_video.field_rate);
171//		fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond
172//			/ fInputFormat.u.raw_video.field_rate);
173//	}
174
175	parameters->quality = fEncodeParameters.quality;
176
177	return B_OK;
178}
179
180
181status_t
182AVCodecEncoder::SetEncodeParameters(encode_parameters* parameters)
183{
184	TRACE("AVCodecEncoder::SetEncodeParameters(%p)\n", parameters);
185
186	if (fFramesWritten > 0)
187		return B_NOT_SUPPORTED;
188
189	fEncodeParameters.quality = parameters->quality;
190	TRACE("  quality: %.5f\n", parameters->quality);
191	if (fEncodeParameters.quality == 0.0f) {
192		TRACE("  using default quality (1.0)\n");
193		fEncodeParameters.quality = 1.0f;
194	}
195
196// TODO: Auto-bit_rate versus user supplied. See above.
197//	int avgBytesPerSecond = 0;
198//	int maxBytesPerSecond = 0;
199//
200//	if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
201//		avgBytesPerSecond = (int)(parameters->avg_field_size
202//			* fInputFormat.u.raw_audio.frame_rate);
203//		maxBytesPerSecond = (int)(parameters->max_field_size
204//			* fInputFormat.u.raw_audio.frame_rate);
205//	} else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
206//		avgBytesPerSecond = (int)(parameters->avg_field_size
207//			* fInputFormat.u.raw_video.field_rate);
208//		maxBytesPerSecond = (int)(parameters->max_field_size
209//			* fInputFormat.u.raw_video.field_rate);
210//	}
211//
212//	if (maxBytesPerSecond < avgBytesPerSecond)
213//		maxBytesPerSecond = avgBytesPerSecond;
214//
215//	// Reset these, so we can tell the difference between uninitialized
216//	// and initialized...
217//	if (avgBytesPerSecond > 0) {
218//		fCodecContext->bit_rate = avgBytesPerSecond * 8;
219//		fCodecContext->bit_rate_tolerance = (maxBytesPerSecond
220//			- avgBytesPerSecond) * 8;
221//		fBitRateControlledByUser = true;
222//	}
223
224	return _Setup();
225}
226
227
228status_t
229AVCodecEncoder::Encode(const void* buffer, int64 frameCount,
230	media_encode_info* info)
231{
232	TRACE("AVCodecEncoder::Encode(%p, %" B_PRId64 ", %p)\n", buffer, frameCount, info);
233
234	if (!_OpenCodecIfNeeded())
235		return B_NO_INIT;
236
237	if (fInputFormat.type == B_MEDIA_RAW_AUDIO)
238		return _EncodeAudio(buffer, frameCount, info);
239	else if (fInputFormat.type == B_MEDIA_RAW_VIDEO)
240		return _EncodeVideo(buffer, frameCount, info);
241	else
242		return B_NO_INIT;
243}
244
245
246// #pragma mark -
247
248
249static int
250get_channel_count(AVCodecContext* context)
251{
252#if LIBAVCODEC_VERSION_MAJOR >= 60
253	return context->ch_layout.nb_channels;
254#else
255	return context->channels;
256#endif
257}
258
259
260static void
261set_channel_count(AVCodecContext* context, int count)
262{
263#if LIBAVCODEC_VERSION_MAJOR >= 60
264	context->ch_layout.nb_channels = count;
265#else
266	context->channels = count;
267#endif
268}
269
270
271status_t
272AVCodecEncoder::_Setup()
273{
274	TRACE("AVCodecEncoder::_Setup\n");
275
276	int rawBitRate;
277
278	if (fCodecContext != NULL) {
279		avcodec_close(fCodecContext);
280		avcodec_free_context(&fCodecContext);
281	}
282
283	fCodecContext = avcodec_alloc_context3(fCodec);
284	if (fCodecContext == NULL)
285		return B_NO_INIT;
286
287	if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
288		TRACE("  B_MEDIA_RAW_VIDEO\n");
289
290		// Check input parameters
291		AVPixelFormat pixFmt = colorspace_to_pixfmt(
292			fInputFormat.u.raw_video.display.format);
293		if (pixFmt == AV_PIX_FMT_NONE) {
294			TRACE("Invalid input colorspace\n");
295			return B_BAD_DATA;
296		}
297
298		// frame rate
299		fCodecContext->time_base = (AVRational){1, (int)fInputFormat.u.raw_video.field_rate};
300		fCodecContext->framerate = (AVRational){(int)fInputFormat.u.raw_video.field_rate, 1};
301
302		// video size
303		fCodecContext->width = fInputFormat.u.raw_video.display.line_width;
304		fCodecContext->height = fInputFormat.u.raw_video.display.line_count;
305		fCodecContext->gop_size = 12;
306
307		// TODO: Fix pixel format or setup conversion method...
308		if (fCodec->pix_fmts != NULL) {
309			for (int i = 0; fCodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
310				// Use the last supported pixel format, which we hope is the
311				// one with the best quality.
312				fCodecContext->pix_fmt = fCodec->pix_fmts[i];
313			}
314		}
315
316		// TODO: Setup rate control:
317//		fCodecContext->rate_emu = 0;
318//		fCodecContext->rc_eq = NULL;
319//		fCodecContext->rc_max_rate = 0;
320//		fCodecContext->rc_min_rate = 0;
321		// TODO: Try to calculate a good bit rate...
322		rawBitRate = (int)(fCodecContext->width * fCodecContext->height * 2
323			* fInputFormat.u.raw_video.field_rate) * 8;
324
325		// Pixel aspect ratio
326		fCodecContext->sample_aspect_ratio.num
327			= fInputFormat.u.raw_video.pixel_width_aspect;
328		fCodecContext->sample_aspect_ratio.den
329			= fInputFormat.u.raw_video.pixel_height_aspect;
330		if (fCodecContext->sample_aspect_ratio.num == 0
331			|| fCodecContext->sample_aspect_ratio.den == 0) {
332			av_reduce(&fCodecContext->sample_aspect_ratio.num,
333				&fCodecContext->sample_aspect_ratio.den, fCodecContext->width,
334				fCodecContext->height, 255);
335		}
336
337		// TODO: This should already happen in AcceptFormat()
338		if (fInputFormat.u.raw_video.display.bytes_per_row == 0) {
339			fInputFormat.u.raw_video.display.bytes_per_row
340				= fCodecContext->width * 4;
341		}
342
343		fFrame->pts = 0;
344
345		fSwsContext = sws_getContext(fCodecContext->width,
346			fCodecContext->height, pixFmt,
347			fCodecContext->width, fCodecContext->height,
348			fCodecContext->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
349
350	} else if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
351		TRACE("  B_MEDIA_RAW_AUDIO\n");
352		// frame rate
353		fCodecContext->sample_rate = (int)fInputFormat.u.raw_audio.frame_rate;
354		// channels
355		set_channel_count(fCodecContext, fInputFormat.u.raw_audio.channel_count);
356		// raw bitrate
357		rawBitRate = fCodecContext->sample_rate * get_channel_count(fCodecContext)
358			* (fInputFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * 8;
359		// sample format
360		switch (fInputFormat.u.raw_audio.format) {
361			case media_raw_audio_format::B_AUDIO_FLOAT:
362				fCodecContext->sample_fmt = AV_SAMPLE_FMT_FLT;
363				break;
364			case media_raw_audio_format::B_AUDIO_DOUBLE:
365				fCodecContext->sample_fmt = AV_SAMPLE_FMT_DBL;
366				break;
367			case media_raw_audio_format::B_AUDIO_INT:
368				fCodecContext->sample_fmt = AV_SAMPLE_FMT_S32;
369				break;
370			case media_raw_audio_format::B_AUDIO_SHORT:
371				fCodecContext->sample_fmt = AV_SAMPLE_FMT_S16;
372				break;
373			case media_raw_audio_format::B_AUDIO_UCHAR:
374				fCodecContext->sample_fmt = AV_SAMPLE_FMT_U8;
375				break;
376
377			case media_raw_audio_format::B_AUDIO_CHAR:
378			default:
379				return B_MEDIA_BAD_FORMAT;
380				break;
381		}
382#if LIBAVCODEC_VERSION_MAJOR >= 60
383		if (fInputFormat.u.raw_audio.channel_mask == 0) {
384			// guess the channel mask...
385			av_channel_layout_default(&fCodecContext->ch_layout,
386				fInputFormat.u.raw_audio.channel_count);
387		} else {
388			// The bits match 1:1 for media_multi_channels and FFmpeg defines.
389			av_channel_layout_from_mask(&fCodecContext->ch_layout,
390				fInputFormat.u.raw_audio.channel_mask);
391		}
392#else
393		if (fInputFormat.u.raw_audio.channel_mask == 0) {
394			// guess the channel mask...
395			switch (fInputFormat.u.raw_audio.channel_count) {
396				default:
397				case 2:
398					fCodecContext->channel_layout = AV_CH_LAYOUT_STEREO;
399					break;
400				case 1:
401					fCodecContext->channel_layout = AV_CH_LAYOUT_MONO;
402					break;
403				case 3:
404					fCodecContext->channel_layout = AV_CH_LAYOUT_SURROUND;
405					break;
406				case 4:
407					fCodecContext->channel_layout = AV_CH_LAYOUT_QUAD;
408					break;
409				case 5:
410					fCodecContext->channel_layout = AV_CH_LAYOUT_5POINT0;
411					break;
412				case 6:
413					fCodecContext->channel_layout = AV_CH_LAYOUT_5POINT1;
414					break;
415				case 8:
416					fCodecContext->channel_layout = AV_CH_LAYOUT_7POINT1;
417					break;
418				case 10:
419					fCodecContext->channel_layout = AV_CH_LAYOUT_7POINT1_WIDE;
420					break;
421			}
422		} else {
423			// The bits match 1:1 for media_multi_channels and FFmpeg defines.
424			fCodecContext->channel_layout = fInputFormat.u.raw_audio.channel_mask;
425		}
426#endif
427	} else {
428		TRACE("  UNSUPPORTED MEDIA TYPE!\n");
429		return B_NOT_SUPPORTED;
430	}
431
432	// TODO: Support letting the user overwrite this via
433	// SetEncodeParameters(). See comments there...
434	int wantedBitRate = (int)(rawBitRate / fBitRateScale * fEncodeParameters.quality);
435	if (wantedBitRate == 0)
436		wantedBitRate = (int)(rawBitRate / fBitRateScale);
437
438	fCodecContext->bit_rate = wantedBitRate;
439
440	if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
441		// Some audio encoders support certain bitrates only. Use the
442		// closest match to the wantedBitRate.
443		const int kBitRates[] = {
444			32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000,
445			160000, 192000, 224000, 256000, 320000, 384000, 448000, 512000,
446			576000, 640000
447		};
448		int diff = wantedBitRate;
449		for (unsigned int i = 0; i < sizeof(kBitRates) / sizeof(int); i++) {
450			int currentDiff = abs(wantedBitRate - kBitRates[i]);
451			if (currentDiff < diff) {
452				fCodecContext->bit_rate = kBitRates[i];
453				diff = currentDiff;
454			} else
455				break;
456		}
457	}
458
459	TRACE("  rawBitRate: %d, wantedBitRate: %d (%.1f), context bitrate: %" PRId64 "\n",
460		rawBitRate, wantedBitRate, fEncodeParameters.quality, fCodecContext->bit_rate);
461
462	// Add some known fixes from the FFmpeg API example:
463	if (fCodecContext->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
464		// Just for testing, we also add B frames */
465		fCodecContext->max_b_frames = 2;
466	} else if (fCodecContext->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
467		// Needed to avoid using macroblocks in which some coeffs overflow.
468		// This does not happen with normal video, it just happens here as
469		// the motion of the chroma plane does not match the luma plane.
470		fCodecContext->mb_decision = 2;
471	}
472
473	// Unfortunately, we may fail later, when we try to open the codec
474	// for real... but we need to delay this because we still allow
475	// parameter/quality changes.
476	return B_OK;
477}
478
479
480bool
481AVCodecEncoder::_OpenCodecIfNeeded()
482{
483	if (fCodecInitStatus == CODEC_INIT_DONE)
484		return true;
485
486	if (fCodecInitStatus == CODEC_INIT_FAILED)
487		return false;
488
489	fCodecContext->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
490
491	// Some codecs need this to be set before open
492	fFrame->format = fCodecContext->pix_fmt;
493	fFrame->width = fCodecContext->width;
494	fFrame->height = fCodecContext->height;
495	av_frame_get_buffer(fFrame, 0);
496
497	// Open the codec
498	int result = avcodec_open2(fCodecContext, fCodec, NULL);
499	if (result >= 0)
500		fCodecInitStatus = CODEC_INIT_DONE;
501	else
502		fCodecInitStatus = CODEC_INIT_FAILED;
503
504	TRACE("  avcodec_open(%p, %p): %d\n", fCodecContext, fCodec, result);
505
506	return fCodecInitStatus == CODEC_INIT_DONE;
507
508}
509
510
511status_t
512AVCodecEncoder::_EncodeAudio(const void* _buffer, int64 frameCount,
513	media_encode_info* info)
514{
515	TRACE("AVCodecEncoder::_EncodeAudio(%p, %" B_PRId64 ", %p)\n", _buffer, frameCount, info);
516
517	if (fChunkBuffer == NULL)
518		return B_NO_MEMORY;
519
520	status_t ret = B_OK;
521
522	const uint8* buffer = reinterpret_cast<const uint8*>(_buffer);
523
524	size_t inputSampleSize = fInputFormat.u.raw_audio.format
525		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
526	size_t inputFrameSize = inputSampleSize
527		* fInputFormat.u.raw_audio.channel_count;
528
529	size_t bufferSize = frameCount * inputFrameSize;
530	bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
531
532	if (fCodecContext->frame_size > 1) {
533		// Encoded audio. Things work differently from raw audio. We need
534		// the fAudioFifo to pipe data.
535#if LIBAVCODEC_VERSION_MAJOR >= 60
536		if (av_fifo_grow2(fAudioFifo, bufferSize) < 0) {
537			TRACE("  av_fifo_grow2() failed\n");
538			return B_NO_MEMORY;
539		}
540		av_fifo_write(fAudioFifo, const_cast<uint8*>(buffer), bufferSize);
541#else
542		if (av_fifo_realloc2(fAudioFifo, av_fifo_size(fAudioFifo) + bufferSize) < 0) {
543			TRACE("  av_fifo_realloc2() failed\n");
544			return B_NO_MEMORY;
545		}
546		av_fifo_generic_write(fAudioFifo, const_cast<uint8*>(buffer), bufferSize, NULL);
547#endif
548
549		size_t frameBytes = fCodecContext->frame_size * inputFrameSize;
550		uint8* tempBuffer = new(std::nothrow) uint8[frameBytes];
551		if (tempBuffer == NULL)
552			return B_NO_MEMORY;
553
554		// Encode as many chunks as can be read from the FIFO.
555#if LIBAVCODEC_VERSION_MAJOR >= 60
556		while (av_fifo_can_read(fAudioFifo) >= frameBytes) {
557			av_fifo_read(fAudioFifo, tempBuffer, frameBytes);
558#else
559		while (av_fifo_size(fAudioFifo) >= (int32)frameBytes) {
560			av_fifo_generic_read(fAudioFifo, tempBuffer, frameBytes, NULL);
561#endif
562
563			ret = _EncodeAudio(tempBuffer, frameBytes, fCodecContext->frame_size,
564				info);
565			if (ret != B_OK)
566				break;
567		}
568
569		delete[] tempBuffer;
570	} else {
571		// Raw audio. The number of bytes returned from avcodec_encode_audio()
572		// is always the same as the number of input bytes.
573		return _EncodeAudio(buffer, bufferSize, frameCount,
574			info);
575	}
576
577	return ret;
578}
579
580
581status_t
582AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize,
583	int64 frameCount, media_encode_info* info)
584{
585	status_t ret;
586
587	// Encode one audio chunk/frame.
588	AVPacket* packet = av_packet_alloc();
589	// By leaving these NULL, we let the encoder allocate memory as it needs.
590	// This way we don't risk iving a too small buffer.
591	packet->data = NULL;
592	packet->size = 0;
593
594	int gotPacket = 0;
595
596	if (buffer) {
597		av_frame_unref(fFrame);
598		fFrame->nb_samples = frameCount;
599
600		int count = avcodec_fill_audio_frame(fFrame, get_channel_count(fCodecContext),
601			fCodecContext->sample_fmt, (const uint8_t*)buffer, bufferSize, 1);
602
603		if (count < 0) {
604			TRACE("  avcodec_encode_audio() failed filling data: %d\n", count);
605			av_packet_free(&packet);
606			return B_ERROR;
607		}
608
609		/* Set the presentation time of the frame */
610		fFrame->pts = (bigtime_t)(fFramesWritten * 1000000LL
611			/ fInputFormat.u.raw_audio.frame_rate);
612		fFramesWritten += fFrame->nb_samples;
613
614		ret = avcodec_send_frame(fCodecContext, fFrame);
615		gotPacket = avcodec_receive_packet(fCodecContext, packet) == 0;
616	} else {
617		// If called with NULL, ask the encoder to flush any buffers it may
618		// have pending.
619		ret = avcodec_receive_packet(fCodecContext, packet);
620		gotPacket = (ret == 0);
621	}
622
623	if (buffer && fFrame->extended_data != fFrame->data)
624		av_freep(&fFrame->extended_data);
625
626	if (ret != 0) {
627		TRACE("  avcodec_encode_audio() failed: %s\n", strerror(ret));
628		av_packet_free(&packet);
629		return B_ERROR;
630	}
631
632	fFramesWritten += frameCount;
633
634	if (gotPacket) {
635		// Setup media_encode_info, most important is the time stamp.
636		info->start_time = packet->pts;
637
638		if (packet->flags & AV_PKT_FLAG_KEY)
639			info->flags = B_MEDIA_KEY_FRAME;
640		else
641			info->flags = 0;
642
643		// We got a packet out of the encoder, write it to the output stream
644		ret = WriteChunk(packet->data, packet->size, info);
645		if (ret != B_OK) {
646			TRACE("  error writing chunk: %s\n", strerror(ret));
647			av_packet_free(&packet);
648			return ret;
649		}
650	}
651
652	av_packet_free(&packet);
653	return B_OK;
654}
655
656
657status_t
658AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
659	media_encode_info* info)
660{
661	TRACE_IO("AVCodecEncoder::_EncodeVideo(%p, %lld, %p)\n", buffer, frameCount,
662		info);
663
664	if (fChunkBuffer == NULL)
665		return B_NO_MEMORY;
666
667	AVPacket* pkt = av_packet_alloc();
668	while (frameCount > 0) {
669		int bpr = fInputFormat.u.raw_video.display.bytes_per_row;
670		size_t bufferSize = fInputFormat.u.raw_video.display.line_count * bpr;
671
672		// Run the pixel format conversion
673		const uint8_t* buf8 = (const uint8_t*)buffer;
674		sws_scale(fSwsContext, &buf8, &bpr, 0,
675			fInputFormat.u.raw_video.display.line_count, fFrame->data,
676			fFrame->linesize);
677
678		if (_EncodeVideoFrame(fFrame, pkt, info) == B_OK) {
679			// Skip to the next frame (but usually, there is only one to encode
680			// for video).
681			frameCount--;
682			fFramesWritten++;
683			buffer = (const void*)((const uint8*)buffer + bufferSize);
684		}
685	}
686
687	// TODO: we should pass a NULL AVFrame and enter "draining" mode, then flush buffers
688	// when we have finished and there is no more data. We cannot do that here, though, since
689	// 1. It's not efficient
690	// 2. It's incorrect, since many codecs need the "next" frame to be able to do optimization.
691	// if we drain the codec, they cannot work with the "next" frame.
692	//_EncodeVideoFrame(NULL, pkt, info);
693	//avcodec_flush_buffers(fCodecContext);
694	av_packet_free(&pkt);
695	return B_OK;
696}
697
698
699status_t
700AVCodecEncoder::_EncodeVideoFrame(AVFrame* frame, AVPacket* pkt, media_encode_info* info)
701{
702	// Encode one video chunk/frame.
703	int result = avcodec_send_frame(fCodecContext, frame);
704	if (result < 0) {
705		TRACE("  avcodec_send_frame() failed: %d\n", result);
706		return B_ERROR;
707	}
708
709	// Increase the frame pts as in the ffmpeg sample code
710	if (frame != NULL)
711		frame->pts++;
712
713	while (result == 0) {
714		result = avcodec_receive_packet(fCodecContext, pkt);
715		if (result == 0) {
716			TRACE("  avcodec_receive_packet: received one packet\n");
717			// Maybe we need to use this PTS to calculate start_time:
718			if (pkt->pts != AV_NOPTS_VALUE) {
719				TRACE("  codec frame PTS: %" B_PRId64 " (codec time_base: %d/%d)\n",
720					pkt->pts, fCodecContext->time_base.num,
721					fCodecContext->time_base.den);
722			} else {
723				TRACE("  codec frame PTS: N/A (codec time_base: %d/%d)\n",
724					fCodecContext->time_base.num, fCodecContext->time_base.den);
725			}
726
727			// Setup media_encode_info, most important is the time stamp.
728			info->start_time = (bigtime_t)(fFramesWritten * 1000000LL
729				/ fInputFormat.u.raw_video.field_rate);
730
731			info->flags = 0;
732			if (pkt->flags & AV_PKT_FLAG_KEY)
733				info->flags |= B_MEDIA_KEY_FRAME;
734
735			// Write the chunk
736			result = WriteChunk(pkt->data, pkt->size, info);
737			if (result != B_OK) {
738				TRACE("  error writing chunk: %s\n", strerror(result));
739				break;
740			}
741		}
742		av_packet_unref(pkt);
743	}
744	if (result == AVERROR(EAGAIN))
745		return B_OK;
746
747	TRACE("   _EncodeVideoFrame(): returning...\n");
748	return result;
749}
750
751