3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / media / plugins / ffmpeg / AVCodecEncoder.cpp
blobc6608cb8b8383491ac0f2ecabf7208462efb3e76
1 /*
2 * Copyright 2009-2010, Stephan Amßus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT license.
4 */
7 #include "AVCodecEncoder.h"
9 #include <new>
11 #include <stdio.h>
12 #include <string.h>
14 #include <Application.h>
15 #include <Roster.h>
17 extern "C" {
18 #include "rational.h"
21 #include "EncoderTable.h"
22 #include "gfx_util.h"
25 #undef TRACE
26 //#define TRACE_AV_CODEC_ENCODER
27 #ifdef TRACE_AV_CODEC_ENCODER
28 # define TRACE printf
29 # define TRACE_IO(a...)
30 #else
31 # define TRACE(a...)
32 # define TRACE_IO(a...)
33 #endif
36 static const size_t kDefaultChunkBufferSize = 2 * 1024 * 1024;
38 #if LIBAVCODEC_VERSION_INT < ((54 << 16) | (50 << 8))
39 #define AV_PIX_FMT_NONE PIX_FMT_NONE
40 #define AV_CODEC_ID_NONE CODEC_ID_NONE
41 #define AV_CODEC_ID_MPEG1VIDEO CODEC_ID_MPEG1VIDEO
42 #define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO
43 #endif
44 #if LIBAVCODEC_VERSION_INT < ((55 << 16) | (45 << 8))
45 #define av_frame_alloc avcodec_alloc_frame
46 #define av_frame_unref avcodec_get_frame_defaults
47 #define av_frame_free avcodec_free_frame
48 #endif
51 AVCodecEncoder::AVCodecEncoder(uint32 codecID, int bitRateScale)
53 Encoder(),
54 fBitRateScale(bitRateScale),
55 fCodecID((CodecID)codecID),
56 fCodec(NULL),
57 fOwnContext(avcodec_alloc_context3(NULL)),
58 fContext(fOwnContext),
59 fCodecInitStatus(CODEC_INIT_NEEDED),
60 fFrame(av_frame_alloc()),
61 fSwsContext(NULL),
62 fFramesWritten(0)
64 TRACE("AVCodecEncoder::AVCodecEncoder()\n");
65 _Init();
69 void
70 AVCodecEncoder::_Init()
72 fChunkBuffer = new(std::nothrow) uint8[kDefaultChunkBufferSize];
73 if (fCodecID > 0) {
74 fCodec = avcodec_find_encoder(fCodecID);
75 TRACE(" found AVCodec for %u: %p\n", fCodecID, fCodec);
78 memset(&fInputFormat, 0, sizeof(media_format));
80 fAudioFifo = av_fifo_alloc(0);
82 fDstFrame.data[0] = NULL;
83 fDstFrame.data[1] = NULL;
84 fDstFrame.data[2] = NULL;
85 fDstFrame.data[3] = NULL;
87 fDstFrame.linesize[0] = 0;
88 fDstFrame.linesize[1] = 0;
89 fDstFrame.linesize[2] = 0;
90 fDstFrame.linesize[3] = 0;
92 // Initial parameters, so we know if the user changed them
93 fEncodeParameters.avg_field_size = 0;
94 fEncodeParameters.max_field_size = 0;
95 fEncodeParameters.quality = 1.0f;
99 AVCodecEncoder::~AVCodecEncoder()
101 TRACE("AVCodecEncoder::~AVCodecEncoder()\n");
103 _CloseCodecIfNeeded();
105 if (fSwsContext != NULL)
106 sws_freeContext(fSwsContext);
108 av_fifo_free(fAudioFifo);
110 avpicture_free(&fDstFrame);
111 // NOTE: Do not use avpicture_free() on fSrcFrame!! We fill the picture
112 // data on the fly with the media buffer data passed to Encode().
114 if (fFrame != NULL) {
115 fFrame->data[0] = NULL;
116 fFrame->data[1] = NULL;
117 fFrame->data[2] = NULL;
118 fFrame->data[3] = NULL;
120 fFrame->linesize[0] = 0;
121 fFrame->linesize[1] = 0;
122 fFrame->linesize[2] = 0;
123 fFrame->linesize[3] = 0;
124 av_free(fFrame);
127 av_free(fOwnContext);
129 delete[] fChunkBuffer;
133 status_t
134 AVCodecEncoder::AcceptedFormat(const media_format* proposedInputFormat,
135 media_format* _acceptedInputFormat)
137 TRACE("AVCodecEncoder::AcceptedFormat(%p, %p)\n", proposedInputFormat,
138 _acceptedInputFormat);
140 if (proposedInputFormat == NULL)
141 return B_BAD_VALUE;
143 if (_acceptedInputFormat != NULL) {
144 memcpy(_acceptedInputFormat, proposedInputFormat,
145 sizeof(media_format));
148 return B_OK;
152 status_t
153 AVCodecEncoder::SetUp(const media_format* inputFormat)
155 TRACE("AVCodecEncoder::SetUp()\n");
157 if (fContext == NULL)
158 return B_NO_INIT;
160 if (inputFormat == NULL)
161 return B_BAD_VALUE;
163 // Codec IDs for raw-formats may need to be figured out here.
164 if (fCodec == NULL && fCodecID == AV_CODEC_ID_NONE) {
165 fCodecID = raw_audio_codec_id_for(*inputFormat);
166 if (fCodecID != AV_CODEC_ID_NONE)
167 fCodec = avcodec_find_encoder(fCodecID);
169 if (fCodec == NULL) {
170 TRACE(" encoder not found!\n");
171 return B_NO_INIT;
174 _CloseCodecIfNeeded();
176 fInputFormat = *inputFormat;
177 fFramesWritten = 0;
179 const uchar* userData = inputFormat->user_data;
180 if (*(uint32*)userData == 'ffmp') {
181 userData += sizeof(uint32);
182 // The Writer plugin used is the FFmpeg plugin. It stores the
183 // AVCodecContext pointer in the user data section. Use this
184 // context instead of our own. It requires the Writer living in
185 // the same team, of course.
186 app_info appInfo;
187 if (be_app->GetAppInfo(&appInfo) == B_OK
188 && *(team_id*)userData == appInfo.team) {
189 userData += sizeof(team_id);
190 // Use the AVCodecContext from the Writer. This works better
191 // than using our own context with some encoders.
192 fContext = *(AVCodecContext**)userData;
196 return _Setup();
200 status_t
201 AVCodecEncoder::GetEncodeParameters(encode_parameters* parameters) const
203 TRACE("AVCodecEncoder::GetEncodeParameters(%p)\n", parameters);
205 // TODO: Implement maintaining an automatically calculated bit_rate versus
206 // a user specified (via SetEncodeParameters()) bit_rate. At this point, the
207 // fContext->bit_rate may not yet have been specified (_Setup() was never
208 // called yet). So it cannot work like the code below, but in any case, it's
209 // showing how to convert between the values (albeit untested).
210 // int avgBytesPerSecond = fContext->bit_rate / 8;
211 // int maxBytesPerSecond = (fContext->bit_rate
212 // + fContext->bit_rate_tolerance) / 8;
214 // if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
215 // fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond
216 // / fInputFormat.u.raw_audio.frame_rate);
217 // fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond
218 // / fInputFormat.u.raw_audio.frame_rate);
219 // } else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
220 // fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond
221 // / fInputFormat.u.raw_video.field_rate);
222 // fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond
223 // / fInputFormat.u.raw_video.field_rate);
224 // }
226 parameters->quality = fEncodeParameters.quality;
228 return B_OK;
232 status_t
233 AVCodecEncoder::SetEncodeParameters(encode_parameters* parameters)
235 TRACE("AVCodecEncoder::SetEncodeParameters(%p)\n", parameters);
237 if (fFramesWritten > 0)
238 return B_NOT_SUPPORTED;
240 fEncodeParameters.quality = parameters->quality;
241 TRACE(" quality: %.5f\n", parameters->quality);
242 if (fEncodeParameters.quality == 0.0f) {
243 TRACE(" using default quality (1.0)\n");
244 fEncodeParameters.quality = 1.0f;
247 // TODO: Auto-bit_rate versus user supplied. See above.
248 // int avgBytesPerSecond = 0;
249 // int maxBytesPerSecond = 0;
251 // if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
252 // avgBytesPerSecond = (int)(parameters->avg_field_size
253 // * fInputFormat.u.raw_audio.frame_rate);
254 // maxBytesPerSecond = (int)(parameters->max_field_size
255 // * fInputFormat.u.raw_audio.frame_rate);
256 // } else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
257 // avgBytesPerSecond = (int)(parameters->avg_field_size
258 // * fInputFormat.u.raw_video.field_rate);
259 // maxBytesPerSecond = (int)(parameters->max_field_size
260 // * fInputFormat.u.raw_video.field_rate);
261 // }
263 // if (maxBytesPerSecond < avgBytesPerSecond)
264 // maxBytesPerSecond = avgBytesPerSecond;
266 // // Reset these, so we can tell the difference between uninitialized
267 // // and initialized...
268 // if (avgBytesPerSecond > 0) {
269 // fContext->bit_rate = avgBytesPerSecond * 8;
270 // fContext->bit_rate_tolerance = (maxBytesPerSecond
271 // - avgBytesPerSecond) * 8;
272 // fBitRateControlledByUser = true;
273 // }
275 return _Setup();
279 status_t
280 AVCodecEncoder::Encode(const void* buffer, int64 frameCount,
281 media_encode_info* info)
283 TRACE("AVCodecEncoder::Encode(%p, %lld, %p)\n", buffer, frameCount, info);
285 if (!_OpenCodecIfNeeded())
286 return B_NO_INIT;
288 if (fInputFormat.type == B_MEDIA_RAW_AUDIO)
289 return _EncodeAudio(buffer, frameCount, info);
290 else if (fInputFormat.type == B_MEDIA_RAW_VIDEO)
291 return _EncodeVideo(buffer, frameCount, info);
292 else
293 return B_NO_INIT;
297 // #pragma mark -
300 status_t
301 AVCodecEncoder::_Setup()
303 TRACE("AVCodecEncoder::_Setup\n");
305 int rawBitRate;
307 if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
308 TRACE(" B_MEDIA_RAW_VIDEO\n");
309 // frame rate
310 fContext->time_base.den = (int)fInputFormat.u.raw_video.field_rate;
311 fContext->time_base.num = 1;
312 // video size
313 fContext->width = fInputFormat.u.raw_video.display.line_width;
314 fContext->height = fInputFormat.u.raw_video.display.line_count;
315 fContext->gop_size = 12;
317 // TODO: Fix pixel format or setup conversion method...
318 if (fCodec->pix_fmts != NULL) {
319 for (int i = 0; fCodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
320 // Use the last supported pixel format, which we hope is the
321 // one with the best quality.
322 fContext->pix_fmt = fCodec->pix_fmts[i];
326 // TODO: Setup rate control:
327 // fContext->rate_emu = 0;
328 // fContext->rc_eq = NULL;
329 // fContext->rc_max_rate = 0;
330 // fContext->rc_min_rate = 0;
331 // TODO: Try to calculate a good bit rate...
332 rawBitRate = (int)(fContext->width * fContext->height * 2
333 * fInputFormat.u.raw_video.field_rate) * 8;
335 // Pixel aspect ratio
336 fContext->sample_aspect_ratio.num
337 = fInputFormat.u.raw_video.pixel_width_aspect;
338 fContext->sample_aspect_ratio.den
339 = fInputFormat.u.raw_video.pixel_height_aspect;
340 if (fContext->sample_aspect_ratio.num == 0
341 || fContext->sample_aspect_ratio.den == 0) {
342 av_reduce(&fContext->sample_aspect_ratio.num,
343 &fContext->sample_aspect_ratio.den, fContext->width,
344 fContext->height, 255);
347 // TODO: This should already happen in AcceptFormat()
348 if (fInputFormat.u.raw_video.display.bytes_per_row == 0) {
349 fInputFormat.u.raw_video.display.bytes_per_row
350 = fContext->width * 4;
353 fFrame->pts = 0;
355 // Allocate space for colorspace converted AVPicture
356 // TODO: Check allocations...
357 avpicture_alloc(&fDstFrame, fContext->pix_fmt, fContext->width,
358 fContext->height);
360 // Make the frame point to the data in the converted AVPicture
361 fFrame->data[0] = fDstFrame.data[0];
362 fFrame->data[1] = fDstFrame.data[1];
363 fFrame->data[2] = fDstFrame.data[2];
364 fFrame->data[3] = fDstFrame.data[3];
366 fFrame->linesize[0] = fDstFrame.linesize[0];
367 fFrame->linesize[1] = fDstFrame.linesize[1];
368 fFrame->linesize[2] = fDstFrame.linesize[2];
369 fFrame->linesize[3] = fDstFrame.linesize[3];
371 fSwsContext = sws_getContext(fContext->width, fContext->height,
372 colorspace_to_pixfmt(fInputFormat.u.raw_video.display.format),
373 fContext->width, fContext->height,
374 fContext->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
376 } else if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
377 TRACE(" B_MEDIA_RAW_AUDIO\n");
378 // frame rate
379 fContext->sample_rate = (int)fInputFormat.u.raw_audio.frame_rate;
380 // channels
381 fContext->channels = fInputFormat.u.raw_audio.channel_count;
382 // raw bitrate
383 rawBitRate = fContext->sample_rate * fContext->channels
384 * (fInputFormat.u.raw_audio.format
385 & media_raw_audio_format::B_AUDIO_SIZE_MASK) * 8;
386 // sample format
387 switch (fInputFormat.u.raw_audio.format) {
388 case media_raw_audio_format::B_AUDIO_FLOAT:
389 fContext->sample_fmt = AV_SAMPLE_FMT_FLT;
390 break;
391 case media_raw_audio_format::B_AUDIO_DOUBLE:
392 fContext->sample_fmt = AV_SAMPLE_FMT_DBL;
393 break;
394 case media_raw_audio_format::B_AUDIO_INT:
395 fContext->sample_fmt = AV_SAMPLE_FMT_S32;
396 break;
397 case media_raw_audio_format::B_AUDIO_SHORT:
398 fContext->sample_fmt = AV_SAMPLE_FMT_S16;
399 break;
400 case media_raw_audio_format::B_AUDIO_UCHAR:
401 fContext->sample_fmt = AV_SAMPLE_FMT_U8;
402 break;
404 case media_raw_audio_format::B_AUDIO_CHAR:
405 default:
406 return B_MEDIA_BAD_FORMAT;
407 break;
409 if (fInputFormat.u.raw_audio.channel_mask == 0) {
410 // guess the channel mask...
411 switch (fInputFormat.u.raw_audio.channel_count) {
412 default:
413 case 2:
414 fContext->channel_layout = AV_CH_LAYOUT_STEREO;
415 break;
416 case 1:
417 fContext->channel_layout = AV_CH_LAYOUT_MONO;
418 break;
419 case 3:
420 fContext->channel_layout = AV_CH_LAYOUT_SURROUND;
421 break;
422 case 4:
423 fContext->channel_layout = AV_CH_LAYOUT_QUAD;
424 break;
425 case 5:
426 fContext->channel_layout = AV_CH_LAYOUT_5POINT0;
427 break;
428 case 6:
429 fContext->channel_layout = AV_CH_LAYOUT_5POINT1;
430 break;
431 case 8:
432 fContext->channel_layout = AV_CH_LAYOUT_7POINT1;
433 break;
434 case 10:
435 fContext->channel_layout = AV_CH_LAYOUT_7POINT1_WIDE;
436 break;
438 } else {
439 // The bits match 1:1 for media_multi_channels and FFmpeg defines.
440 fContext->channel_layout = fInputFormat.u.raw_audio.channel_mask;
442 } else {
443 TRACE(" UNSUPPORTED MEDIA TYPE!\n");
444 return B_NOT_SUPPORTED;
447 // TODO: Support letting the user overwrite this via
448 // SetEncodeParameters(). See comments there...
449 int wantedBitRate = (int)(rawBitRate / fBitRateScale
450 * fEncodeParameters.quality);
451 if (wantedBitRate == 0)
452 wantedBitRate = (int)(rawBitRate / fBitRateScale);
454 fContext->bit_rate = wantedBitRate;
456 if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
457 // Some audio encoders support certain bitrates only. Use the
458 // closest match to the wantedBitRate.
459 const int kBitRates[] = {
460 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000,
461 160000, 192000, 224000, 256000, 320000, 384000, 448000, 512000,
462 576000, 640000
464 int diff = wantedBitRate;
465 for (unsigned int i = 0; i < sizeof(kBitRates) / sizeof(int); i++) {
466 int currentDiff = abs(wantedBitRate - kBitRates[i]);
467 if (currentDiff < diff) {
468 fContext->bit_rate = kBitRates[i];
469 diff = currentDiff;
470 } else
471 break;
475 TRACE(" rawBitRate: %d, wantedBitRate: %d (%.1f), "
476 "context bitrate: %d\n", rawBitRate, wantedBitRate,
477 fEncodeParameters.quality, fContext->bit_rate);
479 // Add some known fixes from the FFmpeg API example:
480 if (fContext->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
481 // Just for testing, we also add B frames */
482 fContext->max_b_frames = 2;
483 } else if (fContext->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
484 // Needed to avoid using macroblocks in which some coeffs overflow.
485 // This does not happen with normal video, it just happens here as
486 // the motion of the chroma plane does not match the luma plane.
487 fContext->mb_decision = 2;
490 // Unfortunately, we may fail later, when we try to open the codec
491 // for real... but we need to delay this because we still allow
492 // parameter/quality changes.
493 return B_OK;
497 bool
498 AVCodecEncoder::_OpenCodecIfNeeded()
500 if (fContext != fOwnContext) {
501 // We are using the AVCodecContext of the AVFormatWriter plugin,
502 // and don't maintain it's open/close state.
503 return true;
506 if (fCodecInitStatus == CODEC_INIT_DONE)
507 return true;
509 if (fCodecInitStatus == CODEC_INIT_FAILED)
510 return false;
512 fContext->strict_std_compliance = -2;
514 // Some codecs need this to be set before open
515 fFrame->format = fContext->pix_fmt;
516 fFrame->width = fContext->width;
517 fFrame->height = fContext->height;
519 // Open the codec
520 int result = avcodec_open2(fContext, fCodec, NULL);
521 if (result >= 0)
522 fCodecInitStatus = CODEC_INIT_DONE;
523 else
524 fCodecInitStatus = CODEC_INIT_FAILED;
526 TRACE(" avcodec_open(%p, %p): %d\n", fContext, fCodec, result);
528 return fCodecInitStatus == CODEC_INIT_DONE;
533 void
534 AVCodecEncoder::_CloseCodecIfNeeded()
536 if (fContext != fOwnContext) {
537 // See _OpenCodecIfNeeded().
538 return;
541 if (fCodecInitStatus == CODEC_INIT_DONE) {
542 avcodec_close(fContext);
543 fCodecInitStatus = CODEC_INIT_NEEDED;
548 static const int64 kNoPTSValue = 0x8000000000000000LL;
549 // NOTE: For some reasons, I have trouble with the avcodec.h define:
550 // #define AV_NOPTS_VALUE INT64_C(0x8000000000000000)
551 // INT64_C is not defined here.
553 status_t
554 AVCodecEncoder::_EncodeAudio(const void* _buffer, int64 frameCount,
555 media_encode_info* info)
557 TRACE("AVCodecEncoder::_EncodeAudio(%p, %lld, %p)\n", _buffer, frameCount,
558 info);
560 if (fChunkBuffer == NULL)
561 return B_NO_MEMORY;
563 status_t ret = B_OK;
565 const uint8* buffer = reinterpret_cast<const uint8*>(_buffer);
567 size_t inputSampleSize = fInputFormat.u.raw_audio.format
568 & media_raw_audio_format::B_AUDIO_SIZE_MASK;
569 size_t inputFrameSize = inputSampleSize
570 * fInputFormat.u.raw_audio.channel_count;
572 size_t bufferSize = frameCount * inputFrameSize;
573 bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
575 if (fContext->frame_size > 1) {
576 // Encoded audio. Things work differently from raw audio. We need
577 // the fAudioFifo to pipe data.
578 if (av_fifo_realloc2(fAudioFifo,
579 av_fifo_size(fAudioFifo) + bufferSize) < 0) {
580 TRACE(" av_fifo_realloc2() failed\n");
581 return B_NO_MEMORY;
583 av_fifo_generic_write(fAudioFifo, const_cast<uint8*>(buffer),
584 bufferSize, NULL);
586 int frameBytes = fContext->frame_size * inputFrameSize;
587 uint8* tempBuffer = new(std::nothrow) uint8[frameBytes];
588 if (tempBuffer == NULL)
589 return B_NO_MEMORY;
591 // Encode as many chunks as can be read from the FIFO.
592 while (av_fifo_size(fAudioFifo) >= frameBytes) {
593 av_fifo_generic_read(fAudioFifo, tempBuffer, frameBytes, NULL);
595 ret = _EncodeAudio(tempBuffer, frameBytes, fContext->frame_size,
596 info);
597 if (ret != B_OK)
598 break;
601 delete[] tempBuffer;
602 } else {
603 // Raw audio. The number of bytes returned from avcodec_encode_audio()
604 // is always the same as the number of input bytes.
605 return _EncodeAudio(buffer, bufferSize, frameCount,
606 info);
609 return ret;
613 status_t
614 AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize,
615 int64 frameCount, media_encode_info* info)
617 status_t ret;
619 // Encode one audio chunk/frame.
620 AVPacket packet;
621 av_init_packet(&packet);
622 // By leaving these NULL, we let the encoder allocate memory as it needs.
623 // This way we don't risk iving a too small buffer.
624 packet.data = NULL;
625 packet.size = 0;
627 // We need to wrap our input data into an AVFrame structure.
628 AVFrame frame;
629 int gotPacket = 0;
631 if (buffer) {
632 av_frame_unref(&frame);
634 frame.nb_samples = frameCount;
636 ret = avcodec_fill_audio_frame(&frame, fContext->channels,
637 fContext->sample_fmt, (const uint8_t *) buffer, bufferSize, 1);
639 if (ret != 0)
640 return B_ERROR;
642 /* Set the presentation time of the frame */
643 frame.pts = (bigtime_t)(fFramesWritten * 1000000LL
644 / fInputFormat.u.raw_audio.frame_rate);
645 fFramesWritten += frame.nb_samples;
647 ret = avcodec_encode_audio2(fContext, &packet, &frame, &gotPacket);
648 } else {
649 // If called with NULL, ask the encoder to flush any buffers it may
650 // have pending.
651 ret = avcodec_encode_audio2(fContext, &packet, NULL, &gotPacket);
654 if (buffer && frame.extended_data != frame.data)
655 av_freep(&frame.extended_data);
657 if (ret != 0) {
658 TRACE(" avcodec_encode_audio() failed: %ld\n", ret);
659 return B_ERROR;
662 fFramesWritten += frameCount;
664 if (gotPacket) {
665 if (fContext->coded_frame) {
666 // Store information about the coded frame in the context.
667 fContext->coded_frame->pts = packet.pts;
668 fContext->coded_frame->key_frame = !!(packet.flags & AV_PKT_FLAG_KEY);
671 // Setup media_encode_info, most important is the time stamp.
672 info->start_time = packet.pts;
674 if (packet.flags & AV_PKT_FLAG_KEY)
675 info->flags = B_MEDIA_KEY_FRAME;
676 else
677 info->flags = 0;
679 // We got a packet out of the encoder, write it to the output stream
680 ret = WriteChunk(packet.data, packet.size, info);
681 if (ret != B_OK) {
682 TRACE(" error writing chunk: %s\n", strerror(ret));
683 av_free_packet(&packet);
684 return ret;
688 av_free_packet(&packet);
689 return B_OK;
693 status_t
694 AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
695 media_encode_info* info)
697 TRACE_IO("AVCodecEncoder::_EncodeVideo(%p, %lld, %p)\n", buffer, frameCount,
698 info);
700 if (fChunkBuffer == NULL)
701 return B_NO_MEMORY;
703 status_t ret = B_OK;
705 while (frameCount > 0) {
706 size_t bpr = fInputFormat.u.raw_video.display.bytes_per_row;
707 size_t bufferSize = fInputFormat.u.raw_video.display.line_count * bpr;
709 // We should always get chunky bitmaps, so this code should be safe.
710 fSrcFrame.data[0] = (uint8_t*)buffer;
711 fSrcFrame.linesize[0] = bpr;
713 // Run the pixel format conversion
714 sws_scale(fSwsContext, fSrcFrame.data, fSrcFrame.linesize, 0,
715 fInputFormat.u.raw_video.display.line_count, fDstFrame.data,
716 fDstFrame.linesize);
718 // Encode one video chunk/frame.
719 #if LIBAVCODEC_VERSION_INT < ((55 << 16) | (45 << 8))
720 int usedBytes = avcodec_encode_video(fContext, fChunkBuffer,
721 kDefaultChunkBufferSize, fFrame);
722 #else
723 int gotPacket;
724 AVPacket pkt;
725 pkt.data = NULL;
726 pkt.size = 0;
727 av_init_packet(&pkt);
728 int usedBytes = avcodec_encode_video2(fContext, &pkt, fFrame, &gotPacket);
729 #endif
730 // avcodec.h says we need to set it.
731 fFrame->pts++;
733 if (usedBytes < 0) {
734 TRACE(" avcodec_encode_video() failed: %d\n", usedBytes);
735 return B_ERROR;
738 #if LIBAVCODEC_VERSION_INT < ((55 << 16) | (45 << 8))
739 // Maybe we need to use this PTS to calculate start_time:
740 if (fContext->coded_frame->pts != kNoPTSValue) {
741 TRACE(" codec frame PTS: %lld (codec time_base: %d/%d)\n",
742 fContext->coded_frame->pts, fContext->time_base.num,
743 fContext->time_base.den);
744 } else {
745 TRACE(" codec frame PTS: N/A (codec time_base: %d/%d)\n",
746 fContext->time_base.num, fContext->time_base.den);
748 #else
749 // Maybe we need to use this PTS to calculate start_time:
750 if (pkt.pts != AV_NOPTS_VALUE) {
751 TRACE(" codec frame PTS: %lld (codec time_base: %d/%d)\n",
752 pkt.pts, fContext->time_base.num,
753 fContext->time_base.den);
754 } else {
755 TRACE(" codec frame PTS: N/A (codec time_base: %d/%d)\n",
756 fContext->time_base.num, fContext->time_base.den);
758 #endif
760 // Setup media_encode_info, most important is the time stamp.
761 info->start_time = (bigtime_t)(fFramesWritten * 1000000LL
762 / fInputFormat.u.raw_video.field_rate);
764 info->flags = 0;
765 if (fContext->coded_frame->key_frame)
766 info->flags |= B_MEDIA_KEY_FRAME;
768 // Write the chunk
769 #if LIBAVCODEC_VERSION_INT < ((55 << 16) | (45 << 8))
770 ret = WriteChunk(fChunkBuffer, usedBytes, info);
771 #else
772 ret = WriteChunk(pkt.data, pkt.size, info);
773 #endif
774 if (ret != B_OK) {
775 TRACE(" error writing chunk: %s\n", strerror(ret));
776 break;
779 // Skip to the next frame (but usually, there is only one to encode
780 // for video).
781 frameCount--;
782 fFramesWritten++;
783 buffer = (const void*)((const uint8*)buffer + bufferSize);
786 return ret;