inline void CvCapture_FFMPEG::seek(s64 _frame_number) { _frame_number = std::min(_frame_number, get_total_frames()); int delta = 16; // if we have not grabbed a single frame before first seek, let's read the first frame // and get some valuable information during the process if( first_frame_number < 0 && get_total_frames() > 1 ) grabFrame(); for(;;) { s64 _frame_number_temp = std::max(_frame_number-delta, (s64)0); double sec = (double)_frame_number_temp / get_fps(); s64 time_stamp = ic->streams[video_stream]->start_time; double time_base = r2d(ic->streams[video_stream]->time_base); time_stamp += (s64)(sec / time_base + 0.5); if (get_total_frames() > 1) av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_BACKWARD); avcodec_flush_buffers(ic->streams[video_stream]->codec); if( _frame_number > 0 ) { grabFrame(); if( _frame_number > 1 ) { frame_number = dts_to_frame_number(picture_pts) - first_frame_number; //printf("_frame_number = %d, frame_number = %d, delta = %d\n", // (int)_frame_number, (int)frame_number, delta); if( frame_number < 0 || frame_number > _frame_number-1 ) { if( _frame_number_temp == 0 || delta >= INT_MAX/4 ) break; delta = delta < 16 ? delta*2 : delta*3/2; continue; } while( frame_number < _frame_number-1 ) { if(!grabFrame()) break; } frame_number++; break; } else { frame_number = 1; break; } } else { frame_number = 0; break; } } }
inline bool CvCapture_FFMPEG::grabFrame() { bool valid = false; int got_picture; int count_errs = 0; const int max_number_of_attempts = 1 << 16; if( !ic || !video_st ) return false; if( ic->streams[video_stream]->nb_frames > 0 && frame_number > ic->streams[video_stream]->nb_frames ) return false; av_free_packet (&packet); picture_pts = AV_NOPTS_VALUE_; unsigned long start; unsigned long end; // get the next frame while (!valid) { start = GetTickCount(); //while (1){ int ret = av_read_frame(ic, &packet); //printf("(%s,%d) Size %d ret %d %d\n", __FUNCTION__, __LINE__, packet.size, ret, // GetTickCount() - start); //DumpHex((char *)(packet.data), 20); if (ret == AVERROR(-1)) continue; // } /* else if (ret < 0) break; */ if( packet.stream_index != video_stream ) { //printf("(%s,%d)\n", __FUNCTION__, __LINE__); av_free_packet (&packet); count_errs++; if (count_errs > max_number_of_attempts) break; continue; } start = GetTickCount(); // Decode video frame #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); #elif LIBAVFORMAT_BUILD > 4628 avcodec_decode_video(video_st->codec, picture, &got_picture, packet.data, packet.size); #else avcodec_decode_video(&video_st->codec, picture, &got_picture, packet.data, packet.size); #endif //printf("(%s,%d) avcodec_decode_video2 %d\n", __FUNCTION__, __LINE__, // GetTickCount() - start); // Did we get a video frame? if(got_picture) { //printf("(%s,%d) got_picture %d\n", __FUNCTION__, __LINE__, // GetTickCount() - start); //picture_pts = picture->best_effort_timestamp; if( picture_pts == AV_NOPTS_VALUE_ ) picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts; frame_number++; valid = true; } else { count_errs++; if (count_errs > max_number_of_attempts) break; } av_free_packet (&packet); } if( valid && first_frame_number < 0 ) first_frame_number = dts_to_frame_number(picture_pts); // return if we have a new picture or not return valid; }
bool CvCapture_FFMPEG::grabFrame() { bool valid = false; int got_picture; int count_errs = 0; const int max_number_of_attempts = 1 << 16; if( !ic || !video_st ) return false; if( ic->streams[video_stream]->nb_frames > 0 && frame_number > ic->streams[video_stream]->nb_frames ) return false; av_free_packet (&packet); picture_pts = AV_NOPTS_VALUE_; // get the next frame while (!valid) { int ret = av_read_frame(ic, &packet); if (ret == AVERROR(EAGAIN)) continue; /* else if (ret < 0) break; */ if( packet.stream_index != video_stream ) { av_free_packet (&packet); count_errs++; if (count_errs > max_number_of_attempts) break; continue; } // Decode video frame #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); #elif LIBAVFORMAT_BUILD > 4628 avcodec_decode_video(video_st->codec, picture, &got_picture, packet.data, packet.size); #else avcodec_decode_video(&video_st->codec, picture, &got_picture, packet.data, packet.size); #endif // Did we get a video frame? if(got_picture) { //picture_pts = picture->best_effort_timestamp; if( picture_pts == AV_NOPTS_VALUE_ ) picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts; frame_number++; valid = true; } else { count_errs++; if (count_errs > max_number_of_attempts) break; } av_free_packet (&packet); } if( valid && first_frame_number < 0 ) first_frame_number = dts_to_frame_number(picture_pts); // return if we have a new picture or not return valid; }