+ if (rewound != nullptr) {
+ *rewound = true;
+ }
+ break;
+
+ case QueuedCommand::CHANGE_RATE:
+ // Change the origin to the last played frame.
+ start = compute_frame_start(last_pts, pts_origin, video_timebase, start, rate);
+ pts_origin = last_pts;
+ rate = cmd.new_rate;
+ break;
+ }
+ }
+ return false;
+}
+
+namespace {
+
+} // namespace
+
+AVFrameWithDeleter FFmpegCapture::decode_frame(AVFormatContext *format_ctx, AVCodecContext *video_codec_ctx, AVCodecContext *audio_codec_ctx,
+ const std::string &pathname, int video_stream_index, int audio_stream_index,
+ FrameAllocator::Frame *audio_frame, AudioFormat *audio_format, int64_t *audio_pts, bool *error)
+{
+ *error = false;
+
+ // Read packets until we have a frame or there are none left.
+ bool frame_finished = false;
+ AVFrameWithDeleter audio_avframe = av_frame_alloc_unique();
+ AVFrameWithDeleter video_avframe = av_frame_alloc_unique();
+ bool eof = false;
+ *audio_pts = -1;
+ do {
+ AVPacket pkt;
+ unique_ptr<AVPacket, decltype(av_packet_unref)*> pkt_cleanup(
+ &pkt, av_packet_unref);
+ av_init_packet(&pkt);
+ pkt.data = nullptr;
+ pkt.size = 0;
+ if (av_read_frame(format_ctx, &pkt) == 0) {
+ if (pkt.stream_index == audio_stream_index && audio_callback != nullptr) {
+ audio_callback(&pkt, format_ctx->streams[audio_stream_index]->time_base);
+ }
+ if (pkt.stream_index == video_stream_index) {
+ if (avcodec_send_packet(video_codec_ctx, &pkt) < 0) {
+ fprintf(stderr, "%s: Cannot send packet to video codec.\n", pathname.c_str());
+ *error = true;
+ return AVFrameWithDeleter(nullptr);
+ }
+ } else if (pkt.stream_index == audio_stream_index) {
+ if (*audio_pts == -1) {
+ *audio_pts = pkt.pts;
+ }
+ if (avcodec_send_packet(audio_codec_ctx, &pkt) < 0) {
+ fprintf(stderr, "%s: Cannot send packet to audio codec.\n", pathname.c_str());
+ *error = true;
+ return AVFrameWithDeleter(nullptr);
+ }
+ }
+ } else {
+ eof = true; // Or error, but ignore that for the time being.