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, %" B_PRId64 ", %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), context bitrate: %" PRId64 "\n", 420 rawBitRate, wantedBitRate, fEncodeParameters.quality, fCodecContext->bit_rate); 421 422 // Add some known fixes from the FFmpeg API example: 423 if (fCodecContext->codec_id == AV_CODEC_ID_MPEG2VIDEO) { 424 // Just for testing, we also add B frames */ 425 fCodecContext->max_b_frames = 2; 426 } else if (fCodecContext->codec_id == AV_CODEC_ID_MPEG1VIDEO) { 427 // Needed to avoid using macroblocks in which some coeffs overflow. 428 // This does not happen with normal video, it just happens here as 429 // the motion of the chroma plane does not match the luma plane. 430 fCodecContext->mb_decision = 2; 431 } 432 433 // Unfortunately, we may fail later, when we try to open the codec 434 // for real... but we need to delay this because we still allow 435 // parameter/quality changes. 436 return B_OK; 437 } 438 439 440 bool 441 AVCodecEncoder::_OpenCodecIfNeeded() 442 { 443 if (fCodecInitStatus == CODEC_INIT_DONE) 444 return true; 445 446 if (fCodecInitStatus == CODEC_INIT_FAILED) 447 return false; 448 449 fCodecContext->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; 450 451 // Some codecs need this to be set before open 452 fFrame->format = fCodecContext->pix_fmt; 453 fFrame->width = fCodecContext->width; 454 fFrame->height = fCodecContext->height; 455 av_frame_get_buffer(fFrame, 0); 456 457 // Open the codec 458 int result = avcodec_open2(fCodecContext, fCodec, NULL); 459 if (result >= 0) 460 fCodecInitStatus = CODEC_INIT_DONE; 461 else 462 fCodecInitStatus = CODEC_INIT_FAILED; 463 464 TRACE(" avcodec_open(%p, %p): %d\n", fCodecContext, fCodec, result); 465 466 return fCodecInitStatus == CODEC_INIT_DONE; 467 468 } 469 470 471 status_t 472 AVCodecEncoder::_EncodeAudio(const void* _buffer, int64 frameCount, 473 media_encode_info* info) 474 { 475 TRACE("AVCodecEncoder::_EncodeAudio(%p, %" B_PRId64 ", %p)\n", _buffer, frameCount, info); 476 477 if (fChunkBuffer == NULL) 478 return B_NO_MEMORY; 479 480 status_t ret = B_OK; 481 482 const uint8* buffer = reinterpret_cast<const uint8*>(_buffer); 483 484 size_t inputSampleSize = fInputFormat.u.raw_audio.format 485 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 486 size_t inputFrameSize = inputSampleSize 487 * fInputFormat.u.raw_audio.channel_count; 488 489 size_t bufferSize = frameCount * inputFrameSize; 490 bufferSize = min_c(bufferSize, kDefaultChunkBufferSize); 491 492 if (fCodecContext->frame_size > 1) { 493 // Encoded audio. Things work differently from raw audio. We need 494 // the fAudioFifo to pipe data. 495 if (av_fifo_realloc2(fAudioFifo, 496 av_fifo_size(fAudioFifo) + bufferSize) < 0) { 497 TRACE(" av_fifo_realloc2() failed\n"); 498 return B_NO_MEMORY; 499 } 500 av_fifo_generic_write(fAudioFifo, const_cast<uint8*>(buffer), 501 bufferSize, NULL); 502 503 int frameBytes = fCodecContext->frame_size * inputFrameSize; 504 uint8* tempBuffer = new(std::nothrow) uint8[frameBytes]; 505 if (tempBuffer == NULL) 506 return B_NO_MEMORY; 507 508 // Encode as many chunks as can be read from the FIFO. 509 while (av_fifo_size(fAudioFifo) >= frameBytes) { 510 av_fifo_generic_read(fAudioFifo, tempBuffer, frameBytes, NULL); 511 512 ret = _EncodeAudio(tempBuffer, frameBytes, fCodecContext->frame_size, 513 info); 514 if (ret != B_OK) 515 break; 516 } 517 518 delete[] tempBuffer; 519 } else { 520 // Raw audio. The number of bytes returned from avcodec_encode_audio() 521 // is always the same as the number of input bytes. 522 return _EncodeAudio(buffer, bufferSize, frameCount, 523 info); 524 } 525 526 return ret; 527 } 528 529 530 status_t 531 AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, 532 int64 frameCount, media_encode_info* info) 533 { 534 status_t ret; 535 536 // Encode one audio chunk/frame. 537 AVPacket* packet = av_packet_alloc(); 538 // By leaving these NULL, we let the encoder allocate memory as it needs. 539 // This way we don't risk iving a too small buffer. 540 packet->data = NULL; 541 packet->size = 0; 542 543 int gotPacket = 0; 544 545 if (buffer) { 546 av_frame_unref(fFrame); 547 fFrame->nb_samples = frameCount; 548 549 int count = avcodec_fill_audio_frame(fFrame, fCodecContext->channels, 550 fCodecContext->sample_fmt, (const uint8_t *) buffer, bufferSize, 1); 551 552 if (count < 0) { 553 TRACE(" avcodec_encode_audio() failed filling data: %d\n", count); 554 av_packet_free(&packet); 555 return B_ERROR; 556 } 557 558 /* Set the presentation time of the frame */ 559 fFrame->pts = (bigtime_t)(fFramesWritten * 1000000LL 560 / fInputFormat.u.raw_audio.frame_rate); 561 fFramesWritten += fFrame->nb_samples; 562 563 ret = avcodec_send_frame(fCodecContext, fFrame); 564 gotPacket = avcodec_receive_packet(fCodecContext, packet) == 0; 565 } else { 566 // If called with NULL, ask the encoder to flush any buffers it may 567 // have pending. 568 ret = avcodec_receive_packet(fCodecContext, packet); 569 gotPacket = (ret == 0); 570 } 571 572 if (buffer && fFrame->extended_data != fFrame->data) 573 av_freep(&fFrame->extended_data); 574 575 if (ret != 0) { 576 TRACE(" avcodec_encode_audio() failed: %s\n", strerror(ret)); 577 av_packet_free(&packet); 578 return B_ERROR; 579 } 580 581 fFramesWritten += frameCount; 582 583 if (gotPacket) { 584 // Setup media_encode_info, most important is the time stamp. 585 info->start_time = packet->pts; 586 587 if (packet->flags & AV_PKT_FLAG_KEY) 588 info->flags = B_MEDIA_KEY_FRAME; 589 else 590 info->flags = 0; 591 592 // We got a packet out of the encoder, write it to the output stream 593 ret = WriteChunk(packet->data, packet->size, info); 594 if (ret != B_OK) { 595 TRACE(" error writing chunk: %s\n", strerror(ret)); 596 av_packet_free(&packet); 597 return ret; 598 } 599 } 600 601 av_packet_free(&packet); 602 return B_OK; 603 } 604 605 606 status_t 607 AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount, 608 media_encode_info* info) 609 { 610 TRACE_IO("AVCodecEncoder::_EncodeVideo(%p, %lld, %p)\n", buffer, frameCount, 611 info); 612 613 if (fChunkBuffer == NULL) 614 return B_NO_MEMORY; 615 616 AVPacket* pkt = av_packet_alloc(); 617 while (frameCount > 0) { 618 int bpr = fInputFormat.u.raw_video.display.bytes_per_row; 619 size_t bufferSize = fInputFormat.u.raw_video.display.line_count * bpr; 620 621 // Run the pixel format conversion 622 const uint8_t* buf8 = (const uint8_t*)buffer; 623 sws_scale(fSwsContext, &buf8, &bpr, 0, 624 fInputFormat.u.raw_video.display.line_count, fFrame->data, 625 fFrame->linesize); 626 627 if (_EncodeVideoFrame(fFrame, pkt, info) == B_OK) { 628 // Skip to the next frame (but usually, there is only one to encode 629 // for video). 630 frameCount--; 631 fFramesWritten++; 632 buffer = (const void*)((const uint8*)buffer + bufferSize); 633 } 634 } 635 636 // TODO: we should pass a NULL AVFrame and enter "draining" mode, then flush buffers 637 // when we have finished and there is no more data. We cannot do that here, though, since 638 // 1. It's not efficient 639 // 2. It's incorrect, since many codecs need the "next" frame to be able to do optimization. 640 // if we drain the codec, they cannot work with the "next" frame. 641 //_EncodeVideoFrame(NULL, pkt, info); 642 //avcodec_flush_buffers(fCodecContext); 643 av_packet_free(&pkt); 644 return B_OK; 645 } 646 647 648 status_t 649 AVCodecEncoder::_EncodeVideoFrame(AVFrame* frame, AVPacket* pkt, media_encode_info* info) 650 { 651 // Encode one video chunk/frame. 652 int result = avcodec_send_frame(fCodecContext, frame); 653 if (result < 0) { 654 TRACE(" avcodec_send_frame() failed: %d\n", result); 655 return B_ERROR; 656 } 657 658 // Increase the frame pts as in the ffmpeg sample code 659 if (frame != NULL) 660 frame->pts++; 661 662 while (result == 0) { 663 result = avcodec_receive_packet(fCodecContext, pkt); 664 if (result == 0) { 665 TRACE(" avcodec_receive_packet: received one packet\n"); 666 // Maybe we need to use this PTS to calculate start_time: 667 if (pkt->pts != AV_NOPTS_VALUE) { 668 TRACE(" codec frame PTS: %" B_PRId64 " (codec time_base: %d/%d)\n", 669 pkt->pts, fCodecContext->time_base.num, 670 fCodecContext->time_base.den); 671 } else { 672 TRACE(" codec frame PTS: N/A (codec time_base: %d/%d)\n", 673 fCodecContext->time_base.num, fCodecContext->time_base.den); 674 } 675 676 // Setup media_encode_info, most important is the time stamp. 677 info->start_time = (bigtime_t)(fFramesWritten * 1000000LL 678 / fInputFormat.u.raw_video.field_rate); 679 680 info->flags = 0; 681 if (pkt->flags & AV_PKT_FLAG_KEY) 682 info->flags |= B_MEDIA_KEY_FRAME; 683 684 // Write the chunk 685 result = WriteChunk(pkt->data, pkt->size, info); 686 if (result != B_OK) { 687 TRACE(" error writing chunk: %s\n", strerror(result)); 688 break; 689 } 690 } 691 av_packet_unref(pkt); 692 } 693 if (result == AVERROR(EAGAIN)) 694 return B_OK; 695 696 TRACE(" _EncodeVideoFrame(): returning...\n"); 697 return result; 698 } 699 700