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