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