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.
376{
379 return 0;
380
381 const size_t required =
static_cast<size_t>(
m_video->out_linesize) *
m_video->out_height;
384
385 const size_t frame_bytes = vc.get_frame_byte_size();
386 const int packed_stride = static_cast<int>(
388
389 uint64_t decoded = 0;
390
391 AVPacket* pkt = av_packet_alloc();
392 AVFrame* frame = av_frame_alloc();
393 if (!pkt || !frame) {
394 av_packet_free(&pkt);
395 av_frame_free(&frame);
396 return 0;
397 }
398
399 uint8_t* sws_dst[1] = {
m_sws_buf.data() };
400 int sws_stride[1] = {
m_video->out_linesize };
401
402 auto write_frame_to_ring = [&]() -> bool {
404 if (idx >= vc.get_total_source_frames())
405 return false;
406
407 uint8_t* dest = vc.mutable_slot_ptr(idx);
408 if (!dest)
409 return false;
410
411 sws_scale(
m_video->sws_context,
412 frame->data, frame->linesize,
413 0,
static_cast<int>(
m_video->height),
414 sws_dst, sws_stride);
415
416 if (
m_video->out_linesize == packed_stride) {
417 std::memcpy(dest,
m_sws_buf.data(), frame_bytes);
418 } else {
419 for (uint32_t row = 0; row <
m_video->out_height; ++row) {
420 std::memcpy(
421 dest + static_cast<size_t>(row) * packed_stride,
423 static_cast<size_t>(packed_stride));
424 }
425 }
426
427 vc.commit_frame(idx);
429 ++decoded;
430
431 av_frame_unref(frame);
432 return true;
433 };
434
435 while (decoded < batch_size) {
436 int ret = av_read_frame(
m_demux->format_context, pkt);
437
438 if (ret < 0) {
439 if (ret == AVERROR_EOF) {
440 avcodec_send_packet(
m_video->codec_context,
nullptr);
441 } else {
442 break;
443 }
444 }
else if (pkt->stream_index !=
m_video->stream_index) {
445 av_packet_unref(pkt);
446 continue;
447 } else {
448 ret = avcodec_send_packet(
m_video->codec_context, pkt);
449 av_packet_unref(pkt);
450 if (ret < 0 && ret != AVERROR(EAGAIN))
451 continue;
452 }
453
454 while (decoded < batch_size) {
455 ret = avcodec_receive_frame(
m_video->codec_context, frame);
456 if (ret == AVERROR(EAGAIN))
457 break;
458 if (ret == AVERROR_EOF)
459 goto done;
460 if (ret < 0) {
461 av_frame_unref(frame);
462 break;
463 }
464
465 if (!write_frame_to_ring())
466 goto done;
467 }
468
469 if (ret == AVERROR_EOF)
470 break;
471 }
472
473done:
474 av_packet_free(&pkt);
475 av_frame_free(&frame);
476 return decoded;
477}
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