Decode up to batch_size frames starting at m_decode_head.
Pumps packets in a loop, draining multiple frames per packet batch. Returns the number of frames actually decoded.
387{
390 return 0;
391
392 const size_t required =
static_cast<size_t>(
m_video->out_linesize) *
m_video->out_height;
395
396 const size_t frame_bytes = vc.get_frame_byte_size();
397 const int packed_stride = static_cast<int>(
399
400 uint64_t decoded = 0;
401
402 AVPacket* pkt = av_packet_alloc();
403 AVFrame* frame = av_frame_alloc();
404 if (!pkt || !frame) {
405 av_packet_free(&pkt);
406 av_frame_free(&frame);
407 return 0;
408 }
409
410 uint8_t* sws_dst[1] = {
m_sws_buf.data() };
411 int sws_stride[1] = {
m_video->out_linesize };
412
413 auto write_frame_to_ring = [&]() -> bool {
415 if (idx >= vc.get_total_source_frames())
416 return false;
417
418 uint8_t* dest = vc.mutable_slot_ptr(idx);
419 if (!dest)
420 return false;
421
422 sws_scale(
m_video->sws_context,
423 frame->data, frame->linesize,
424 0,
static_cast<int>(
m_video->height),
425 sws_dst, sws_stride);
426
427 if (
m_video->out_linesize == packed_stride) {
428 std::memcpy(dest,
m_sws_buf.data(), frame_bytes);
429 } else {
430 for (uint32_t row = 0; row <
m_video->out_height; ++row) {
431 std::memcpy(
432 dest + static_cast<size_t>(row) * packed_stride,
434 static_cast<size_t>(packed_stride));
435 }
436 }
437
438 vc.commit_frame(idx);
440 ++decoded;
441
442 av_frame_unref(frame);
443 return true;
444 };
445
446 while (decoded < batch_size) {
447 int ret = av_read_frame(
m_demux->format_context, pkt);
448
449 if (ret < 0) {
450 if (ret == AVERROR_EOF) {
451 avcodec_send_packet(
m_video->codec_context,
nullptr);
452 } else {
453 break;
454 }
455 }
else if (pkt->stream_index !=
m_video->stream_index) {
456 av_packet_unref(pkt);
457 continue;
458 } else {
459 ret = avcodec_send_packet(
m_video->codec_context, pkt);
460 av_packet_unref(pkt);
461 if (ret < 0 && ret != AVERROR(EAGAIN))
462 continue;
463 }
464
465 while (decoded < batch_size) {
466 ret = avcodec_receive_frame(
m_video->codec_context, frame);
467 if (ret == AVERROR(EAGAIN))
468 break;
469 if (ret == AVERROR_EOF)
470 goto done;
471 if (ret < 0) {
472 av_frame_unref(frame);
473 break;
474 }
475
476 if (!write_frame_to_ring())
477 goto done;
478 }
479
480 if (ret == AVERROR_EOF)
481 break;
482 }
483
484done:
485 av_packet_free(&pkt);
486 av_frame_free(&frame);
487 return decoded;
488}
std::vector< uint8_t > m_sws_buf
One-frame sws scratch buffer (padded linesize, reused by decode thread).
std::shared_ptr< FFmpegDemuxContext > m_demux
std::shared_mutex m_context_mutex
std::shared_ptr< VideoStreamContext > m_video
std::atomic< uint64_t > m_decode_head