1+ #include <stdio.h>
2+ #include <stdlib.h>
3+ #include <string.h>
4+ #include <time.h>
5+
6+ #include <libavcodec/avcodec.h>
7+ #include <libavformat/avformat.h>
8+ #include <libavutil/timestamp.h>
9+ #include <libswscale/swscale.h>
10+
11+ #define ADDITIONAL_FRAMES 30
12+
13+ double get_time () {
14+ struct timespec ts ;
15+ clock_gettime (CLOCK_MONOTONIC , & ts );
16+ return ts .tv_sec + ts .tv_nsec / 1e9 ;
17+ }
18+
19+ int decode_frames_with_library (const char * filename , const char * decoder_library , int64_t seek_frame ) {
20+ AVFormatContext * format_ctx = NULL ;
21+ AVCodecContext * codec_ctx = NULL ;
22+ const AVCodec * codec = NULL ;
23+ AVFrame * frame = NULL ;
24+ AVPacket * packet = NULL ;
25+ int video_stream_index = -1 ;
26+ int ret ;
27+
28+ if (avformat_open_input (& format_ctx , filename , NULL , NULL ) < 0 ) {
29+ fprintf (stderr , "Could not open file %s\n" , filename );
30+ return -1 ;
31+ }
32+
33+ if (avformat_find_stream_info (format_ctx , NULL ) < 0 ) {
34+ fprintf (stderr , "Could not find stream information\n" );
35+ avformat_close_input (& format_ctx );
36+ return -1 ;
37+ }
38+
39+ for (int i = 0 ; i < format_ctx -> nb_streams ; i ++ ) {
40+ if (format_ctx -> streams [i ]-> codecpar -> codec_type == AVMEDIA_TYPE_VIDEO ) {
41+ video_stream_index = i ;
42+ break ;
43+ }
44+ }
45+
46+ if (video_stream_index == -1 ) {
47+ fprintf (stderr , "Could not find video stream\n" );
48+ avformat_close_input (& format_ctx );
49+ return -1 ;
50+ }
51+
52+ AVCodecParameters * codecpar = format_ctx -> streams [video_stream_index ]-> codecpar ;
53+
54+ codec = avcodec_find_decoder_by_name (decoder_library );
55+ if (!codec ) {
56+ fprintf (stderr , "Decoder library %s not found\n" , decoder_library );
57+ avformat_close_input (& format_ctx );
58+ return -1 ;
59+ }
60+
61+ if (codec -> id != codecpar -> codec_id ) {
62+ fprintf (stderr , "Specified decoder library %s does not match the video codec\n" , decoder_library );
63+ avformat_close_input (& format_ctx );
64+ return -1 ;
65+ }
66+
67+ codec_ctx = avcodec_alloc_context3 (codec );
68+ if (!codec_ctx ) {
69+ fprintf (stderr , "Could not allocate codec context\n" );
70+ avformat_close_input (& format_ctx );
71+ return -1 ;
72+ }
73+
74+
75+
76+
77+ if (avcodec_parameters_to_context (codec_ctx , codecpar ) < 0 ) {
78+ fprintf (stderr , "Could not copy codec parameters to context\n" );
79+ avcodec_free_context (& codec_ctx );
80+ avformat_close_input (& format_ctx );
81+ return -1 ;
82+ }
83+ // Set threading options
84+ codec_ctx -> thread_count = 0 ; // Let FFmpeg decide the number of threads
85+ codec_ctx -> thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE ; // Use both frame and slice threading
86+ codec_ctx -> flags2 |= AV_CODEC_FLAG2_FAST ;
87+ codec_ctx -> flags |= AV_CODEC_FLAG_LOW_DELAY ;
88+
89+ if (avcodec_open2 (codec_ctx , codec , NULL ) < 0 ) {
90+ fprintf (stderr , "Could not open codec\n" );
91+ avcodec_free_context (& codec_ctx );
92+ avformat_close_input (& format_ctx );
93+ return -1 ;
94+ }
95+
96+ frame = av_frame_alloc ();
97+ packet = av_packet_alloc ();
98+ if (!frame || !packet ) {
99+ fprintf (stderr , "Could not allocate frame or packet\n" );
100+ av_frame_free (& frame );
101+ av_packet_free (& packet );
102+ avcodec_free_context (& codec_ctx );
103+ avformat_close_input (& format_ctx );
104+ return -1 ;
105+ }
106+
107+ // Convert frame number to timestamp
108+ AVStream * video_stream = format_ctx -> streams [video_stream_index ];
109+ int64_t seek_timestamp = av_rescale_q (seek_frame ,
110+ av_inv_q (video_stream -> avg_frame_rate ),
111+ video_stream -> time_base );
112+
113+
114+
115+ int frames_decoded = 0 ;
116+ double total_decoding_time = 0.0 ;
117+ double first_frame_time = 0.0 ;
118+ clock_t start_time = clock ();
119+
120+ if (av_seek_frame (format_ctx , video_stream_index , seek_timestamp , AVSEEK_FLAG_BACKWARD ) < 0 ) {
121+ fprintf (stderr , "Error while seeking\n" );
122+ av_frame_free (& frame );
123+ av_packet_free (& packet );
124+ avcodec_free_context (& codec_ctx );
125+ avformat_close_input (& format_ctx );
126+ return -1 ;
127+ }
128+
129+ avcodec_flush_buffers (codec_ctx );
130+
131+ clock_t end_time = clock ();
132+ double frame_time = ((double ) (end_time - start_time )) / CLOCKS_PER_SEC ;
133+ fprintf (stderr , "Decoder seek: %s\nFirstFrame: %.6f\n" , decoder_library , frame_time );
134+ start_time = clock ();
135+ struct timespec start_time2 ;
136+ clock_gettime (CLOCK_MONOTONIC , & start_time2 );
137+
138+
139+ while (av_read_frame (format_ctx , packet ) >= 0 && frames_decoded <= ADDITIONAL_FRAMES ) {
140+ clock_t end_time = clock ();
141+ double frame_time = ((double ) (end_time - start_time )) / CLOCKS_PER_SEC ;
142+ fprintf (stderr , "avread_frame: %.6f\n" , frame_time );
143+ if (packet -> stream_index == video_stream_index ) {
144+
145+ clock_t send_start_time = clock ();
146+ ret = avcodec_send_packet (codec_ctx , packet );
147+ if (ret < 0 ) {
148+ fprintf (stderr , "Error sending packet for decoding\n" );
149+ break ;
150+ }
151+
152+ clock_t end_time = clock ();
153+ double frame_time = ((double ) (end_time - send_start_time )) / CLOCKS_PER_SEC ;
154+ fprintf (stderr , "send_packet: %.6f\n" , frame_time );
155+
156+ while (ret >= 0 ) {
157+ clock_t receive_time_start = clock ();
158+ ret = avcodec_receive_frame (codec_ctx , frame );
159+ if (ret == AVERROR (EAGAIN ) || ret == AVERROR_EOF ) {
160+ //fprintf(stderr, "ERROR: %d\n", ret);
161+ break ;
162+ } else if (ret < 0 ) {
163+ fprintf (stderr , "Error during decoding\n" );
164+ goto end ;
165+ }
166+
167+ clock_t end_time = clock ();
168+ double frame_time = ((double ) (end_time - start_time )) / CLOCKS_PER_SEC ;
169+ double receive_frame_time = ((double ) (end_time - receive_time_start )) / CLOCKS_PER_SEC ;
170+ struct timespec end_time2 ;
171+ clock_gettime (CLOCK_MONOTONIC , & end_time2 );
172+ double elapsed_seconds = (end_time2 .tv_sec - start_time2 .tv_sec ) +
173+ (end_time2 .tv_nsec - start_time2 .tv_nsec ) / 1e9 ;
174+ fprintf (stderr , "Decoder: %s Frame: %02d Duration:%.6f ReceiveDuration:%.6f Duration2:%.6f\n" ,
175+ decoder_library , frames_decoded , frame_time , receive_frame_time , elapsed_seconds );
176+ total_decoding_time += frame_time ;
177+
178+ if (frames_decoded == 0 ) {
179+ first_frame_time = frame_time ;
180+ printf ("Decoder: %s\nFirstFrame: %.6f\n" ,
181+ decoder_library , frame_time );
182+ total_decoding_time = 0 ;
183+ start_time = clock (); // We reset, since we dont want the following times to include the first time.
184+ }
185+
186+ frames_decoded ++ ;
187+
188+ if (frames_decoded > ADDITIONAL_FRAMES ) {
189+ break ;
190+ }
191+
192+ start_time = end_time ; // For timing the next frame
193+ }
194+ }
195+ av_packet_unref (packet );
196+ }
197+
198+ end :
199+ if (frames_decoded > 1 ) {
200+ double avg_subsequent_frame_time = (total_decoding_time - first_frame_time ) / (frames_decoded - 1 );
201+ printf ("Average: %.6f\n" ,
202+ avg_subsequent_frame_time );
203+ }
204+
205+ av_frame_free (& frame );
206+ av_packet_free (& packet );
207+ avcodec_free_context (& codec_ctx );
208+ avformat_close_input (& format_ctx );
209+
210+ return 0 ;
211+ }
212+
213+ int main (int argc , char * argv []) {
214+ if (argc != 4 ) {
215+ fprintf (stderr , "Usage: %s <input_file> <decoder_library> <seek_frame>\n" , argv [0 ]);
216+ return 1 ;
217+ }
218+
219+ const char * input_file = argv [1 ];
220+ const char * decoder_library = argv [2 ];
221+ int64_t seek_frame = atoll (argv [3 ]);
222+
223+ decode_frames_with_library (input_file , decoder_library , seek_frame );
224+
225+ return 0 ;
226+ }
0 commit comments