OpenShot Library | libopenshot  0.1.1
FFmpegReader.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for FFmpegReader class
4  * @author Jonathan Thomas <jonathan@openshot.org>, Fabrice Bellard
5  *
6  * @section LICENSE
7  *
8  * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard
9  * (http://www.openshotstudios.com). This file is part of
10  * OpenShot Library (http://www.openshot.org), an open-source project
11  * dedicated to delivering high quality video editing and animation solutions
12  * to the world.
13  *
14  * This file is originally based on the Libavformat API example, and then modified
15  * by the libopenshot project.
16  *
17  * OpenShot Library (libopenshot) is free software: you can redistribute it
18  * and/or modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation, either version 3 of the
20  * License, or (at your option) any later version.
21  *
22  * OpenShot Library (libopenshot) is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #include "../include/FFmpegReader.h"
32 
33 using namespace openshot;
34 
36  : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
37  audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false),
38  check_fps(false), enable_seek(true), rescaler_position(0), num_of_rescalers(OPEN_MP_NUM_PROCESSORS), is_open(false),
39  seek_audio_frame_found(0), seek_video_frame_found(0), prev_samples(0), prev_pts(0),
40  pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0),
41  current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0) {
42 
43  // Initialize FFMpeg, and register all formats and codecs
44  av_register_all();
45  avcodec_register_all();
46 
47  // Init cache
48  working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 60, info.width, info.height, info.sample_rate, info.channels);
49  final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels);
50 
51  // Open and Close the reader, to populate it's attributes (such as height, width, etc...)
52  Open();
53  Close();
54 }
55 
57  if (is_open)
58  // Auto close reader if not already done
59  Close();
60 }
61 
62 // Init a collection of software rescalers (thread safe)
63 void FFmpegReader::InitScalers()
64 {
65  // Init software rescalers vector (many of them, one for each thread)
66  for (int x = 0; x < num_of_rescalers; x++)
67  {
68  SwsContext *img_convert_ctx = sws_getContext(info.width, info.height, pCodecCtx->pix_fmt, info.width,
69  info.height, PIX_FMT_RGBA, SWS_FAST_BILINEAR, NULL, NULL, NULL);
70 
71  // Add rescaler to vector
72  image_rescalers.push_back(img_convert_ctx);
73  }
74 }
75 
76 // This struct holds the associated video frame and starting sample # for an audio packet.
77 int AudioLocation::is_near(AudioLocation location, int samples_per_frame, int amount)
78 {
79  // Is frame even close to this one?
80  if (abs(location.frame - frame) >= 2)
81  // This is too far away to be considered
82  return false;
83 
84  int sample_diff = abs(location.sample_start - sample_start);
85  if (location.frame == frame && sample_diff >= 0 && sample_diff <= amount)
86  // close
87  return true;
88 
89  // new frame is after
90  if (location.frame > frame)
91  {
92  // remaining samples + new samples
93  sample_diff = (samples_per_frame - sample_start) + location.sample_start;
94  if (sample_diff >= 0 && sample_diff <= amount)
95  return true;
96  }
97 
98  // new frame is before
99  if (location.frame < frame)
100  {
101  // remaining new samples + old samples
102  sample_diff = (samples_per_frame - location.sample_start) + sample_start;
103  if (sample_diff >= 0 && sample_diff <= amount)
104  return true;
105  }
106 
107  // not close
108  return false;
109 }
110 
111 // Remove & deallocate all software scalers
112 void FFmpegReader::RemoveScalers()
113 {
114  // Close all rescalers
115  for (int x = 0; x < num_of_rescalers; x++)
116  sws_freeContext(image_rescalers[x]);
117 
118  // Clear vector
119  image_rescalers.clear();
120 }
121 
123 {
124  // Open reader if not already open
125  if (!is_open)
126  {
127  // Initialize format context
128  pFormatCtx = NULL;
129 
130  // Open video file
131  if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0)
132  throw InvalidFile("File could not be opened.", path);
133 
134  // Retrieve stream information
135  if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
136  throw NoStreamsFound("No streams found in file.", path);
137 
138  videoStream = -1;
139  audioStream = -1;
140  // Loop through each stream, and identify the video and audio stream index
141  for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
142  {
143  // Is this a video stream?
144  if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && videoStream < 0) {
145  videoStream = i;
146  }
147  // Is this an audio stream?
148  if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0) {
149  audioStream = i;
150  }
151  }
152  if (videoStream == -1 && audioStream == -1)
153  throw NoStreamsFound("No video or audio streams found in this file.", path);
154 
155  // Is there a video stream?
156  if (videoStream != -1)
157  {
158  // Set the stream index
159  info.video_stream_index = videoStream;
160 
161  // Set the codec and codec context pointers
162  pStream = pFormatCtx->streams[videoStream];
163  pCodecCtx = pFormatCtx->streams[videoStream]->codec;
164 
165  // Set number of threads equal to number of processors + 1
166  pCodecCtx->thread_count = OPEN_MP_NUM_PROCESSORS;
167 
168  // Find the decoder for the video stream
169  AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
170  if (pCodec == NULL) {
171  throw InvalidCodec("A valid video codec could not be found for this file.", path);
172  }
173  // Open video codec
174  if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
175  throw InvalidCodec("A video codec was found, but could not be opened.", path);
176 
177  // Update the File Info struct with video details (if a video stream is found)
178  UpdateVideoInfo();
179 
180  // Init rescalers (if video stream detected)
181  InitScalers();
182  }
183 
184  // Is there an audio stream?
185  if (audioStream != -1)
186  {
187  // Set the stream index
188  info.audio_stream_index = audioStream;
189 
190  // Get a pointer to the codec context for the audio stream
191  aStream = pFormatCtx->streams[audioStream];
192  aCodecCtx = pFormatCtx->streams[audioStream]->codec;
193 
194  // Set number of threads equal to number of processors + 1
195  aCodecCtx->thread_count = OPEN_MP_NUM_PROCESSORS;
196 
197  // Find the decoder for the audio stream
198  AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
199  if (aCodec == NULL) {
200  throw InvalidCodec("A valid audio codec could not be found for this file.", path);
201  }
202  // Open audio codec
203  if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0)
204  throw InvalidCodec("An audio codec was found, but could not be opened.", path);
205 
206  // Update the File Info struct with audio details (if an audio stream is found)
207  UpdateAudioInfo();
208  }
209 
210  // Init previous audio location to zero
211  previous_packet_location.frame = -1;
212  previous_packet_location.sample_start = 0;
213 
214  // Adjust cache size based on size of frame and audio
217 
218  // Mark as "open"
219  is_open = true;
220  }
221 }
222 
224 {
225  // Close all objects, if reader is 'open'
226  if (is_open)
227  {
228  // Mark as "closed"
229  is_open = false;
230 
231  // Close the codec
232  if (info.has_video)
233  {
234  // Clear image scalers
235  RemoveScalers();
236 
237  avcodec_flush_buffers(pCodecCtx);
238  avcodec_close(pCodecCtx);
239  }
240  if (info.has_audio)
241  {
242  avcodec_flush_buffers(aCodecCtx);
243  avcodec_close(aCodecCtx);
244  }
245 
246  // Clear final cache
247  final_cache.Clear();
248  working_cache.Clear();
249 
250  // Clear processed lists
251  {
252  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
253  processed_video_frames.clear();
254  processed_audio_frames.clear();
255  processing_video_frames.clear();
256  processing_audio_frames.clear();
257  missing_video_frames.clear();
258  }
259 
260  // Close the video file
261  avformat_close_input(&pFormatCtx);
262  av_freep(&pFormatCtx);
263 
264  // Reset some variables
265  last_frame = 0;
266  largest_frame_processed = 0;
267  seek_audio_frame_found = 0;
268  seek_video_frame_found = 0;
269  current_video_frame = 0;
270  has_missing_frames = false;
271  }
272 }
273 
274 void FFmpegReader::UpdateAudioInfo()
275 {
276  // Set values of FileInfo struct
277  info.has_audio = true;
278  info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
279  info.acodec = aCodecCtx->codec->name;
280  info.channels = aCodecCtx->channels;
281  if (aCodecCtx->channel_layout == 0)
282  aCodecCtx->channel_layout = av_get_default_channel_layout( aCodecCtx->channels );;
283  info.channel_layout = (ChannelLayout) aCodecCtx->channel_layout;
284  info.sample_rate = aCodecCtx->sample_rate;
285  info.audio_bit_rate = aCodecCtx->bit_rate;
286 
287  // Set audio timebase
288  info.audio_timebase.num = aStream->time_base.num;
289  info.audio_timebase.den = aStream->time_base.den;
290 
291  // Get timebase of audio stream (if valid) and greater than the current duration
292  if (aStream->duration > 0.0f && aStream->duration > info.duration)
293  info.duration = aStream->duration * info.audio_timebase.ToDouble();
294 
295  // Check for an invalid video length
296  if (info.has_video && info.video_length <= 0)
297  {
298  // Calculate the video length from the audio duration
300  }
301 
302  // Set video timebase (if no video stream was found)
303  if (!info.has_video)
304  {
305  // Set a few important default video settings (so audio can be divided into frames)
306  info.fps.num = 24;
307  info.fps.den = 1;
308  info.video_timebase.num = 1;
309  info.video_timebase.den = 24;
311  info.width = 720;
312  info.height = 480;
313 
314  }
315 
316 }
317 
318 void FFmpegReader::UpdateVideoInfo()
319 {
320  // Set values of FileInfo struct
321  info.has_video = true;
322  info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
323  info.height = pCodecCtx->height;
324  info.width = pCodecCtx->width;
325  info.vcodec = pCodecCtx->codec->name;
326  info.video_bit_rate = pFormatCtx->bit_rate;
327  if (!check_fps)
328  {
329  // set frames per second (fps)
330  info.fps.num = pStream->avg_frame_rate.num;
331  info.fps.den = pStream->avg_frame_rate.den;
332  }
333 
334  if (pStream->sample_aspect_ratio.num != 0)
335  {
336  info.pixel_ratio.num = pStream->sample_aspect_ratio.num;
337  info.pixel_ratio.den = pStream->sample_aspect_ratio.den;
338  }
339  else if (pCodecCtx->sample_aspect_ratio.num != 0)
340  {
341  info.pixel_ratio.num = pCodecCtx->sample_aspect_ratio.num;
342  info.pixel_ratio.den = pCodecCtx->sample_aspect_ratio.den;
343  }
344  else
345  {
346  info.pixel_ratio.num = 1;
347  info.pixel_ratio.den = 1;
348  }
349 
350  info.pixel_format = pCodecCtx->pix_fmt;
351 
352  // Calculate the DAR (display aspect ratio)
354 
355  // Reduce size fraction
356  size.Reduce();
357 
358  // Set the ratio based on the reduced fraction
359  info.display_ratio.num = size.num;
360  info.display_ratio.den = size.den;
361 
362  // Set the video timebase
363  info.video_timebase.num = pStream->time_base.num;
364  info.video_timebase.den = pStream->time_base.den;
365 
366  // Set the duration in seconds, and video length (# of frames)
367  info.duration = pStream->duration * info.video_timebase.ToDouble();
368 
369  // Check for valid duration (if found)
370  if (info.duration <= 0.0f && pFormatCtx->duration >= 0)
371  // Use the format's duration
372  info.duration = pFormatCtx->duration / AV_TIME_BASE;
373 
374  // Calculate duration from filesize and bitrate (if any)
375  if (info.duration <= 0.0f && info.video_bit_rate > 0 && info.file_size > 0)
376  // Estimate from bitrate, total bytes, and framerate
378 
379  // No duration found in stream of file
380  if (info.duration <= 0.0f)
381  {
382  // No duration is found in the video stream
383  info.duration = -1;
384  info.video_length = -1;
385  is_duration_known = false;
386  }
387  else
388  {
389  // Yes, a duration was found
390  is_duration_known = true;
391 
392  // Calculate number of frames
394  }
395 
396  // Override an invalid framerate
397  if (info.fps.ToFloat() > 120.0f || (info.fps.num == 0 || info.fps.den == 0))
398  {
399  // Set a few important default video settings (so audio can be divided into frames)
400  info.fps.num = 24;
401  info.fps.den = 1;
402  info.video_timebase.num = 1;
403  info.video_timebase.den = 24;
404 
405  // Calculate number of frames
407  }
408 
409 }
410 
411 
412 tr1::shared_ptr<Frame> FFmpegReader::GetFrame(long int requested_frame) throw(OutOfBoundsFrame, ReaderClosed, TooManySeeks)
413 {
414  // Check for open reader (or throw exception)
415  if (!is_open)
416  throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path);
417 
418  // Adjust for a requested frame that is too small or too large
419  if (requested_frame < 1)
420  requested_frame = 1;
421  if (requested_frame > info.video_length && is_duration_known)
422  requested_frame = info.video_length;
423  if (info.has_video && info.video_length == 0)
424  // Invalid duration of video file
425  throw InvalidFile("Could not detect the duration of the video or audio stream.", path);
426 
427  // Debug output
428  AppendDebugMethod("FFmpegReader::GetFrame", "requested_frame", requested_frame, "last_frame", last_frame, "", -1, "", -1, "", -1, "", -1);
429 
430  // Check the cache for this frame
431  tr1::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
432  if (frame) {
433  // Debug output
434  AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame", requested_frame, "", -1, "", -1, "", -1, "", -1, "", -1);
435 
436  // Return the cached frame
437  return frame;
438  }
439  else
440  {
441  // Create a scoped lock, allowing only a single thread to run the following code at one time
442  const GenericScopedLock<CriticalSection> lock(getFrameCriticalSection);
443 
444  // Check the cache a 2nd time (due to a potential previous lock)
445  if (has_missing_frames)
446  CheckMissingFrame(requested_frame);
447  frame = final_cache.GetFrame(requested_frame);
448  if (frame) {
449  // Debug output
450  AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame on 2nd look", requested_frame, "", -1, "", -1, "", -1, "", -1, "", -1);
451 
452  // Return the cached frame
453  return frame;
454  }
455 
456  // Frame is not in cache
457  // Reset seek count
458  seek_count = 0;
459 
460  // Check for first frame (always need to get frame 1 before other frames, to correctly calculate offsets)
461  if (last_frame == 0 && requested_frame != 1)
462  // Get first frame
463  ReadStream(1);
464 
465  // Are we within X frames of the requested frame?
466  long int diff = requested_frame - last_frame;
467  if (diff >= 1 && diff <= 20)
468  {
469  // Continue walking the stream
470  return ReadStream(requested_frame);
471  }
472  else
473  {
474  // Greater than 30 frames away, or backwards, we need to seek to the nearest key frame
475  if (enable_seek)
476  // Only seek if enabled
477  Seek(requested_frame);
478 
479  else if (!enable_seek && diff < 0)
480  {
481  // Start over, since we can't seek, and the requested frame is smaller than our position
482  Close();
483  Open();
484  }
485 
486  // Then continue walking the stream
487  return ReadStream(requested_frame);
488  }
489 
490  }
491 }
492 
493 // Read the stream until we find the requested Frame
494 tr1::shared_ptr<Frame> FFmpegReader::ReadStream(long int requested_frame)
495 {
496  // Allocate video frame
497  bool end_of_stream = false;
498  bool check_seek = false;
499  bool frame_finished = false;
500  int packet_error = -1;
501 
502  // Minimum number of packets to process (for performance reasons)
503  int packets_processed = 0;
504  int minimum_packets = OPEN_MP_NUM_PROCESSORS;
505 
506  // Set the number of threads in OpenMP
507  omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
508  // Allow nested OpenMP sections
509  omp_set_nested(true);
510 
511  // Debug output
512  AppendDebugMethod("FFmpegReader::ReadStream", "requested_frame", requested_frame, "OPEN_MP_NUM_PROCESSORS", OPEN_MP_NUM_PROCESSORS, "", -1, "", -1, "", -1, "", -1);
513 
514  #pragma omp parallel
515  {
516  #pragma omp single
517  {
518  // Loop through the stream until the correct frame is found
519  while (true)
520  {
521  // Get the next packet into a local variable called packet
522  packet_error = GetNextPacket();
523 
524  // Wait if too many frames are being processed
525  while (processing_video_frames.size() + processing_audio_frames.size() >= minimum_packets)
526  usleep(2500);
527 
528  // Get the next packet (if any)
529  if (packet_error < 0)
530  {
531  // Break loop when no more packets found
532  end_of_stream = true;
533  break;
534  }
535 
536  // Debug output
537  AppendDebugMethod("FFmpegReader::ReadStream (GetNextPacket)", "requested_frame", requested_frame, "processing_video_frames.size()", processing_video_frames.size(), "processing_audio_frames.size()", processing_audio_frames.size(), "minimum_packets", minimum_packets, "packets_processed", packets_processed, "", -1);
538 
539  // Video packet
540  if (packet->stream_index == videoStream)
541  {
542  // Reset this counter, since we have a video packet
543  num_packets_since_video_frame = 0;
544 
545  // Check the status of a seek (if any)
546  if (is_seeking)
547  #pragma omp critical (openshot_seek)
548  check_seek = CheckSeek(true);
549  else
550  check_seek = false;
551 
552  if (check_seek) {
553  // Remove packet (since this packet is pointless)
554  RemoveAVPacket(packet);
555 
556  // Jump to the next iteration of this loop
557  continue;
558  }
559 
560  // Get the AVFrame from the current packet
561  frame_finished = GetAVFrame();
562 
563  // Check if the AVFrame is finished and set it
564  if (frame_finished)
565  {
566  // Update PTS / Frame Offset (if any)
567  UpdatePTSOffset(true);
568 
569  // Process Video Packet
570  ProcessVideoPacket(requested_frame);
571  }
572 
573  }
574  // Audio packet
575  else if (packet->stream_index == audioStream)
576  {
577  // Increment this (to track # of packets since the last video packet)
578  num_packets_since_video_frame++;
579 
580  // Check the status of a seek (if any)
581  if (is_seeking)
582  #pragma omp critical (openshot_seek)
583  check_seek = CheckSeek(false);
584  else
585  check_seek = false;
586 
587  if (check_seek) {
588  // Remove packet (since this packet is pointless)
589  RemoveAVPacket(packet);
590 
591  // Jump to the next iteration of this loop
592  continue;
593  }
594 
595  // Update PTS / Frame Offset (if any)
596  UpdatePTSOffset(false);
597 
598  // Determine related video frame and starting sample # from audio PTS
599  AudioLocation location = GetAudioPTSLocation(packet->pts);
600 
601  // Process Audio Packet
602  ProcessAudioPacket(requested_frame, location.frame, location.sample_start);
603  }
604 
605  // Check if working frames are 'finished'
606  bool is_cache_found = false;
607  if (!is_seeking) {
608  // Check for any missing frames
609  CheckMissingFrame(requested_frame);
610 
611  // Check for final frames
612  CheckWorkingFrames(false, requested_frame);
613  }
614 
615  // Check if requested 'final' frame is available
616  is_cache_found = (final_cache.GetFrame(requested_frame) != NULL);
617 
618  // Increment frames processed
619  packets_processed++;
620 
621  // Break once the frame is found
622  if ((is_cache_found && packets_processed >= minimum_packets))
623  break;
624 
625  } // end while
626 
627  } // end omp single
628  } // end omp parallel
629 
630  // Debug output
631  AppendDebugMethod("FFmpegReader::ReadStream (Completed)", "packets_processed", packets_processed, "end_of_stream", end_of_stream, "largest_frame_processed", largest_frame_processed, "Working Cache Count", working_cache.Count(), "", -1, "", -1);
632 
633  // End of stream?
634  if (end_of_stream)
635  // Mark the any other working frames as 'finished'
636  CheckWorkingFrames(end_of_stream, requested_frame);
637 
638  // Return requested frame (if found)
639  tr1::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
640  if (frame)
641  // Return prepared frame
642  return frame;
643  else {
644 
645  // Check if largest frame is still cached
646  frame = final_cache.GetFrame(largest_frame_processed);
647  if (frame) {
648  // return the largest processed frame (assuming it was the last in the video file)
649  return frame;
650  }
651  else {
652  // The largest processed frame is no longer in cache, return a blank frame
653  tr1::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
654  f->AddColor(info.width, info.height, "#000");
655  return f;
656  }
657  }
658 
659 }
660 
661 // Get the next packet (if any)
662 int FFmpegReader::GetNextPacket()
663 {
664  int found_packet = 0;
665  AVPacket *next_packet = new AVPacket();
666  found_packet = av_read_frame(pFormatCtx, next_packet);
667 
668  if (found_packet >= 0)
669  {
670  #pragma omp critical (packet_cache)
671  {
672  // Add packet to packet cache
673  packets[next_packet] = next_packet;
674 
675  // Update current packet pointer
676  packet = packets[next_packet];
677  } // end omp critical
678 
679  }
680  else
681  {
682  // Free packet, since it's unused
683  av_free_packet(next_packet);
684  delete next_packet;
685  }
686 
687  // Return if packet was found (or error number)
688  return found_packet;
689 }
690 
691 // Get an AVFrame (if any)
692 bool FFmpegReader::GetAVFrame()
693 {
694  int frameFinished = -1;
695 
696  // Decode video frame
697  AVFrame *next_frame = AV_ALLOCATE_FRAME();
698  #pragma omp critical (packet_cache)
699  avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
700 
701  // is frame finished
702  if (frameFinished)
703  {
704  // AVFrames are clobbered on the each call to avcodec_decode_video, so we
705  // must make a copy of the image data before this method is called again.
706  AVPicture *copyFrame = new AVPicture();
707  avpicture_alloc(copyFrame, pCodecCtx->pix_fmt, info.width, info.height);
708  av_picture_copy(copyFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width, info.height);
709 
710  #pragma omp critical (packet_cache)
711  {
712  // add to AVFrame cache (if frame finished)
713  frames[copyFrame] = copyFrame;
714  pFrame = frames[copyFrame];
715  }
716 
717  // Detect interlaced frame (only once)
718  if (!check_interlace)
719  {
720  check_interlace = true;
721  info.interlaced_frame = next_frame->interlaced_frame;
722  info.top_field_first = next_frame->top_field_first;
723  }
724 
725  }
726  else
727  {
728  // Remove packet (since this packet is pointless)
729  RemoveAVPacket(packet);
730  }
731 
732  // deallocate the frame
733  AV_FREE_FRAME(&next_frame);
734 
735  // Did we get a video frame?
736  return frameFinished;
737 }
738 
739 // Check the current seek position and determine if we need to seek again
740 bool FFmpegReader::CheckSeek(bool is_video)
741 {
742  // Are we seeking for a specific frame?
743  if (is_seeking)
744  {
745  // Determine if both an audio and video packet have been decoded since the seek happened.
746  // If not, allow the ReadStream method to keep looping
747  if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found))
748  return false;
749 
750  // Check for both streams
751  if ((info.has_video && !seek_video_frame_found) || (info.has_audio && !seek_audio_frame_found))
752  return false;
753 
754  // Determine max seeked frame
755  long int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame
756  if (seek_video_frame_found > max_seeked_frame)
757  max_seeked_frame = seek_video_frame_found;
758 
759  // determine if we are "before" the requested frame
760  if (max_seeked_frame >= seeking_frame)
761  {
762  // SEEKED TOO FAR
763  AppendDebugMethod("FFmpegReader::CheckSeek (Too far, seek again)", "is_video_seek", is_video_seek, "max_seeked_frame", max_seeked_frame, "seeking_frame", seeking_frame, "seeking_pts", seeking_pts, "seek_video_frame_found", seek_video_frame_found, "seek_audio_frame_found", seek_audio_frame_found);
764 
765  // Seek again... to the nearest Keyframe
766  Seek(seeking_frame - (20 * seek_count * seek_count));
767  }
768  else
769  {
770  // SEEK WORKED
771  AppendDebugMethod("FFmpegReader::CheckSeek (Successful)", "is_video_seek", is_video_seek, "current_pts", packet->pts, "seeking_pts", seeking_pts, "seeking_frame", seeking_frame, "seek_video_frame_found", seek_video_frame_found, "seek_audio_frame_found", seek_audio_frame_found);
772 
773  // Seek worked, and we are "before" the requested frame
774  is_seeking = false;
775  seeking_frame = 0;
776  seeking_pts = -1;
777  }
778  }
779 
780  // return the pts to seek to (if any)
781  return is_seeking;
782 }
783 
784 // Process a video packet
785 void FFmpegReader::ProcessVideoPacket(long int requested_frame)
786 {
787  // Calculate current frame #
788  long int current_frame = ConvertVideoPTStoFrame(GetVideoPTS());
789 
790  // Track 1st video packet after a successful seek
791  if (!seek_video_frame_found && is_seeking)
792  seek_video_frame_found = current_frame;
793 
794  // Are we close enough to decode the frame? and is this frame # valid?
795  if ((!has_missing_frames and current_frame < (requested_frame - 20)) or (current_frame == -1))
796  {
797  // Remove frame and packet
798  RemoveAVFrame(pFrame);
799  RemoveAVPacket(packet);
800 
801  // Debug output
802  AppendDebugMethod("FFmpegReader::ProcessVideoPacket (Skipped)", "requested_frame", requested_frame, "current_frame", current_frame, "", -1, "", -1, "", -1, "", -1);
803 
804  // Skip to next frame without decoding or caching
805  return;
806  }
807 
808  // Debug output
809  AppendDebugMethod("FFmpegReader::ProcessVideoPacket (Before)", "requested_frame", requested_frame, "current_frame", current_frame, "", -1, "", -1, "", -1, "", -1);
810 
811  // Init some things local (for OpenMP)
812  PixelFormat pix_fmt = pCodecCtx->pix_fmt;
813  int height = info.height;
814  int width = info.width;
815  long int video_length = info.video_length;
816  AVPacket *my_packet = packets[packet];
817  AVPicture *my_frame = frames[pFrame];
818 
819  // Get a scaling context
820  SwsContext *img_convert_ctx = image_rescalers[rescaler_position];
821  rescaler_position++;
822  if (rescaler_position == num_of_rescalers)
823  rescaler_position = 0;
824 
825  // Add video frame to list of processing video frames
826  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
827  processing_video_frames[current_frame] = current_frame;
828 
829  #pragma omp task firstprivate(current_frame, my_packet, my_frame, height, width, video_length, pix_fmt, img_convert_ctx)
830  {
831  // Create variables for a RGB Frame (since most videos are not in RGB, we must convert it)
832  AVFrame *pFrameRGB = NULL;
833  int numBytes;
834  uint8_t *buffer = NULL;
835 
836  // Allocate an AVFrame structure
837  pFrameRGB = AV_ALLOCATE_FRAME();
838  if (pFrameRGB == NULL)
839  throw OutOfBoundsFrame("Convert Image Broke!", current_frame, video_length);
840 
841  // Determine required buffer size and allocate buffer
842  numBytes = avpicture_get_size(PIX_FMT_RGBA, width, height);
843  buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t) * 2);
844 
845  // Assign appropriate parts of buffer to image planes in pFrameRGB
846  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
847  // of AVPicture
848  avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGBA, width, height);
849 
850  // Resize / Convert to RGB
851  sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0,
852  height, pFrameRGB->data, pFrameRGB->linesize);
853 
854  // Create or get the existing frame object
855  tr1::shared_ptr<Frame> f = CreateFrame(current_frame);
856 
857  // Add Image data to frame
858  f->AddImage(width, height, 4, QImage::Format_RGBA8888, buffer);
859 
860  // Update working cache
861  working_cache.Add(f->number, f);
862 
863  // Keep track of last last_video_frame
864  last_video_frame = f;
865 
866  // Free the RGB image
867  av_free(buffer);
868  AV_FREE_FRAME(&pFrameRGB);
869 
870  // Remove frame and packet
871  RemoveAVFrame(my_frame);
872  RemoveAVPacket(my_packet);
873 
874  // Remove video frame from list of processing video frames
875  {
876  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
877  processing_video_frames.erase(current_frame);
878  processed_video_frames[current_frame] = current_frame;
879  }
880 
881  // Debug output
882  AppendDebugMethod("FFmpegReader::ProcessVideoPacket (After)", "requested_frame", requested_frame, "current_frame", current_frame, "f->number", f->number, "", -1, "", -1, "", -1);
883 
884  } // end omp task
885 
886 }
887 
888 // Process an audio packet
889 void FFmpegReader::ProcessAudioPacket(long int requested_frame, long int target_frame, int starting_sample)
890 {
891  // Track 1st audio packet after a successful seek
892  if (!seek_audio_frame_found && is_seeking)
893  seek_audio_frame_found = target_frame;
894 
895  // Are we close enough to decode the frame's audio?
896  if (!has_missing_frames and target_frame < (requested_frame - 20))
897  {
898  // Remove packet
899  RemoveAVPacket(packet);
900 
901  // Debug output
902  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Skipped)", "requested_frame", requested_frame, "target_frame", target_frame, "starting_sample", starting_sample, "", -1, "", -1, "", -1);
903 
904  // Skip to next frame without decoding or caching
905  return;
906  }
907 
908  // Init some local variables (for OpenMP)
909  AVPacket *my_packet = packets[packet];
910 
911  // Debug output
912  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Before)", "requested_frame", requested_frame, "target_frame", target_frame, "starting_sample", starting_sample, "", -1, "", -1, "", -1);
913 
914  // Init an AVFrame to hold the decoded audio samples
915  int frame_finished = 0;
916  AVFrame *audio_frame = AV_ALLOCATE_FRAME();
917  AV_RESET_FRAME(audio_frame);
918 
919  int packet_samples = 0;
920  int data_size = 0;
921 
922  // re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call)
923  int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE;
924  int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, my_packet);
925 
926  if (frame_finished) {
927 
928  // determine how many samples were decoded
929  int planar = av_sample_fmt_is_planar(aCodecCtx->sample_fmt);
930  int plane_size = -1;
931  data_size = av_samples_get_buffer_size(&plane_size,
932  aCodecCtx->channels,
933  audio_frame->nb_samples,
934  aCodecCtx->sample_fmt, 1);
935 
936  // Calculate total number of samples
937  packet_samples = audio_frame->nb_samples * aCodecCtx->channels;
938  }
939 
940  // Estimate the # of samples and the end of this packet's location (to prevent GAPS for the next timestamp)
941  int pts_remaining_samples = packet_samples / info.channels; // Adjust for zero based array
942 
943  // DEBUG (FOR AUDIO ISSUES) - Get the audio packet start time (in seconds)
944  int adjusted_pts = packet->pts + audio_pts_offset;
945  double audio_seconds = double(adjusted_pts) * info.audio_timebase.ToDouble();
946  double sample_seconds = float(pts_total) / info.sample_rate;
947 
948  // Debug output
949  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Decode Info A)", "pts_counter", pts_counter, "PTS", adjusted_pts, "Offset", audio_pts_offset, "PTS Diff", adjusted_pts - prev_pts, "Samples", pts_remaining_samples, "Sample PTS ratio", float(adjusted_pts - prev_pts) / pts_remaining_samples);
950  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Decode Info B)", "Sample Diff", pts_remaining_samples - prev_samples - prev_pts, "Total", pts_total, "PTS Seconds", audio_seconds, "Sample Seconds", sample_seconds, "Seconds Diff", audio_seconds - sample_seconds, "raw samples", packet_samples);
951 
952  // DEBUG (FOR AUDIO ISSUES)
953  prev_pts = adjusted_pts;
954  pts_total += pts_remaining_samples;
955  pts_counter++;
956  prev_samples = pts_remaining_samples;
957 
958  // Add audio frame to list of processing audio frames
959  {
960  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
961  processing_audio_frames.insert(pair<int, int>(previous_packet_location.frame, previous_packet_location.frame));
962  }
963 
964  while (pts_remaining_samples)
965  {
966  // Get Samples per frame (for this frame number)
967  int samples_per_frame = Frame::GetSamplesPerFrame(previous_packet_location.frame, info.fps, info.sample_rate, info.channels);
968 
969  // Calculate # of samples to add to this frame
970  int samples = samples_per_frame - previous_packet_location.sample_start;
971  if (samples > pts_remaining_samples)
972  samples = pts_remaining_samples;
973 
974  // Decrement remaining samples
975  pts_remaining_samples -= samples;
976 
977  if (pts_remaining_samples > 0) {
978  // next frame
979  previous_packet_location.frame++;
980  previous_packet_location.sample_start = 0;
981 
982  // Add audio frame to list of processing audio frames
983  {
984  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
985  processing_audio_frames.insert(pair<int, int>(previous_packet_location.frame, previous_packet_location.frame));
986  }
987 
988  } else {
989  // Increment sample start
990  previous_packet_location.sample_start += samples;
991  }
992  }
993 
994 
995 
996  // Process the audio samples in a separate thread (this includes resampling to 16 bit integer, and storing
997  // in a openshot::Frame object).
998  #pragma omp task firstprivate(requested_frame, target_frame, starting_sample, my_packet, audio_frame)
999  {
1000  // Allocate audio buffer
1001  int16_t *audio_buf = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
1002 
1003  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (ReSample)", "packet_samples", packet_samples, "info.channels", info.channels, "info.sample_rate", info.sample_rate, "aCodecCtx->sample_fmt", aCodecCtx->sample_fmt, "AV_SAMPLE_FMT_S16", AV_SAMPLE_FMT_S16, "", -1);
1004 
1005  // Create output frame
1006  AVFrame *audio_converted = AV_ALLOCATE_FRAME();
1007  AV_RESET_FRAME(audio_converted);
1008  audio_converted->nb_samples = audio_frame->nb_samples;
1009  av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, audio_frame->nb_samples, AV_SAMPLE_FMT_S16, 0);
1010 
1011  AVAudioResampleContext *avr = NULL;
1012  int nb_samples = 0;
1013  #pragma ordered
1014  {
1015  // setup resample context
1016  avr = avresample_alloc_context();
1017  av_opt_set_int(avr, "in_channel_layout", aCodecCtx->channel_layout, 0);
1018  av_opt_set_int(avr, "out_channel_layout", aCodecCtx->channel_layout, 0);
1019  av_opt_set_int(avr, "in_sample_fmt", aCodecCtx->sample_fmt, 0);
1020  av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
1021  av_opt_set_int(avr, "in_sample_rate", info.sample_rate, 0);
1022  av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0);
1023  av_opt_set_int(avr, "in_channels", info.channels, 0);
1024  av_opt_set_int(avr, "out_channels", info.channels, 0);
1025  int r = avresample_open(avr);
1026 
1027  // Convert audio samples
1028  nb_samples = avresample_convert(avr, // audio resample context
1029  audio_converted->data, // output data pointers
1030  audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
1031  audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
1032  audio_frame->data, // input data pointers
1033  audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
1034  audio_frame->nb_samples); // number of input samples to convert
1035  }
1036 
1037  // Copy audio samples over original samples
1038  memcpy(audio_buf, audio_converted->data[0], audio_converted->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * info.channels);
1039 
1040  // Deallocate resample buffer
1041  avresample_close(avr);
1042  avresample_free(&avr);
1043  avr = NULL;
1044 
1045  // Free AVFrames
1046  AV_FREE_FRAME(&audio_frame);
1047  av_free(audio_converted->data[0]);
1048  AV_FREE_FRAME(&audio_converted);
1049 
1050  int starting_frame_number = -1;
1051  bool partial_frame = true;
1052  for (int channel_filter = 0; channel_filter < info.channels; channel_filter++)
1053  {
1054  // Array of floats (to hold samples for each channel)
1055  starting_frame_number = target_frame;
1056  int channel_buffer_size = packet_samples / info.channels;
1057  float *channel_buffer = new float[channel_buffer_size];
1058 
1059  // Init buffer array
1060  for (int z = 0; z < channel_buffer_size; z++)
1061  channel_buffer[z] = 0.0f;
1062 
1063  // Loop through all samples and add them to our Frame based on channel.
1064  // Toggle through each channel number, since channel data is stored like (left right left right)
1065  int channel = 0;
1066  int position = 0;
1067  for (int sample = 0; sample < packet_samples; sample++)
1068  {
1069  // Only add samples for current channel
1070  if (channel_filter == channel)
1071  {
1072  // Add sample (convert from (-32768 to 32768) to (-1.0 to 1.0))
1073  channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 15));
1074 
1075  // Increment audio position
1076  position++;
1077  }
1078 
1079  // increment channel (if needed)
1080  if ((channel + 1) < info.channels)
1081  // move to next channel
1082  channel ++;
1083  else
1084  // reset channel
1085  channel = 0;
1086  }
1087 
1088  // Loop through samples, and add them to the correct frames
1089  int start = starting_sample;
1090  int remaining_samples = channel_buffer_size;
1091  float *iterate_channel_buffer = channel_buffer; // pointer to channel buffer
1092  while (remaining_samples > 0)
1093  {
1094  // Get Samples per frame (for this frame number)
1095  int samples_per_frame = Frame::GetSamplesPerFrame(starting_frame_number, info.fps, info.sample_rate, info.channels);
1096 
1097  // Calculate # of samples to add to this frame
1098  int samples = samples_per_frame - start;
1099  if (samples > remaining_samples)
1100  samples = remaining_samples;
1101 
1102  // Create or get the existing frame object
1103  tr1::shared_ptr<Frame> f = CreateFrame(starting_frame_number);
1104 
1105  // Determine if this frame was "partially" filled in
1106  if (samples_per_frame == start + samples)
1107  partial_frame = false;
1108  else
1109  partial_frame = true;
1110 
1111  // Add samples for current channel to the frame. Reduce the volume to 98%, to prevent
1112  // some louder samples from maxing out at 1.0 (not sure why this happens)
1113  f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 0.98f);
1114 
1115  // Debug output
1116  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (f->AddAudio)", "frame", starting_frame_number, "start", start, "samples", samples, "channel", channel_filter, "partial_frame", partial_frame, "samples_per_frame", samples_per_frame);
1117 
1118  // Add or update cache
1119  working_cache.Add(f->number, f);
1120 
1121  // Decrement remaining samples
1122  remaining_samples -= samples;
1123 
1124  // Increment buffer (to next set of samples)
1125  if (remaining_samples > 0)
1126  iterate_channel_buffer += samples;
1127 
1128  // Increment frame number
1129  starting_frame_number++;
1130 
1131  // Reset starting sample #
1132  start = 0;
1133  }
1134 
1135  // clear channel buffer
1136  delete[] channel_buffer;
1137  channel_buffer = NULL;
1138  iterate_channel_buffer = NULL;
1139  }
1140 
1141  // Clean up some arrays
1142  delete[] audio_buf;
1143  audio_buf = NULL;
1144 
1145  // Remove audio frame from list of processing audio frames
1146  {
1147  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1148  // Update all frames as completed
1149  for (long int f = target_frame; f < starting_frame_number; f++) {
1150  // Remove the frame # from the processing list. NOTE: If more than one thread is
1151  // processing this frame, the frame # will be in this list multiple times. We are only
1152  // removing a single instance of it here.
1153  processing_audio_frames.erase(processing_audio_frames.find(f));
1154 
1155  // Check and see if this frame is also being processed by another thread
1156  if (processing_audio_frames.count(f) == 0)
1157  // No other thread is processing it. Mark the audio as processed (final)
1158  processed_audio_frames[f] = f;
1159  }
1160 
1161  if (target_frame == starting_frame_number) {
1162  // This typically never happens, but just in case, remove the currently processing number
1163  processing_audio_frames.erase(processing_audio_frames.find(target_frame));
1164  }
1165  }
1166 
1167  // Remove this packet
1168  RemoveAVPacket(my_packet);
1169 
1170  // Debug output
1171  AppendDebugMethod("FFmpegReader::ProcessAudioPacket (After)", "requested_frame", requested_frame, "starting_frame", target_frame, "end_frame", starting_frame_number - 1, "", -1, "", -1, "", -1);
1172 
1173  } // end task
1174 
1175 
1176  // TODO: Fix this bug. Wait on the task to complete. This is not ideal, but solves an issue with the
1177  // audio_frame being modified by the next call to this method. I think this is a scope issue with OpenMP.
1178  #pragma omp taskwait
1179 }
1180 
1181 
1182 
1183 // Seek to a specific frame. This is not always frame accurate, it's more of an estimation on many codecs.
1184 void FFmpegReader::Seek(long int requested_frame) throw(TooManySeeks)
1185 {
1186  // Adjust for a requested frame that is too small or too large
1187  if (requested_frame < 1)
1188  requested_frame = 1;
1189  if (requested_frame > info.video_length)
1190  requested_frame = info.video_length;
1191 
1192  // Debug output
1193  AppendDebugMethod("FFmpegReader::Seek", "requested_frame", requested_frame, "seek_count", seek_count, "last_frame", last_frame, "", -1, "", -1, "", -1);
1194 
1195  // Clear working cache (since we are seeking to another location in the file)
1196  working_cache.Clear();
1197 
1198  // Clear processed lists
1199  {
1200  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1201  processing_audio_frames.clear();
1202  processing_video_frames.clear();
1203  processed_video_frames.clear();
1204  processed_audio_frames.clear();
1205  duplicate_video_frames.clear();
1206  missing_video_frames.clear();
1207  }
1208 
1209  // Reset the last frame variable
1210  last_frame = 0;
1211  current_video_frame = 0;
1212  largest_frame_processed = 0;
1213  num_checks_since_final = 0;
1214  num_packets_since_video_frame = 0;
1215  has_missing_frames = false;
1216 
1217  // Increment seek count
1218  seek_count++;
1219 
1220  // If seeking near frame 1, we need to close and re-open the file (this is more reliable than seeking)
1221  int buffer_amount = 6;
1222  if (requested_frame - buffer_amount < 20)
1223  {
1224  // Close and re-open file (basically seeking to frame 1)
1225  Close();
1226  Open();
1227 
1228  // Not actually seeking, so clear these flags
1229  is_seeking = false;
1230  if (seek_count == 1) {
1231  // Don't redefine this on multiple seek attempts for a specific frame
1232  seeking_frame = 1;
1233  seeking_pts = ConvertFrameToVideoPTS(1);
1234  }
1235  seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek
1236  seek_video_frame_found = 0; // used to detect which frames to throw away after a seek
1237  }
1238  else
1239  {
1240  // Seek to nearest key-frame (aka, i-frame)
1241  bool seek_worked = false;
1242  int64_t seek_target = 0;
1243 
1244  // Seek video stream (if any)
1245  if (!seek_worked && info.has_video)
1246  {
1247  seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount);
1248  if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1249  fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->filename);
1250  } else
1251  {
1252  // VIDEO SEEK
1253  is_video_seek = true;
1254  seek_worked = true;
1255  }
1256  }
1257 
1258  // Seek audio stream (if not already seeked... and if an audio stream is found)
1259  if (!seek_worked && info.has_audio)
1260  {
1261  seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount);
1262  if (info.has_audio && av_seek_frame(pFormatCtx, info.audio_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1263  fprintf(stderr, "%s: error while seeking audio stream\n", pFormatCtx->filename);
1264  } else
1265  {
1266  // AUDIO SEEK
1267  is_video_seek = false;
1268  seek_worked = true;
1269  }
1270  }
1271 
1272  // Was the seek successful?
1273  if (seek_worked)
1274  {
1275  // Flush audio buffer
1276  if (info.has_audio)
1277  avcodec_flush_buffers(aCodecCtx);
1278 
1279  // Flush video buffer
1280  if (info.has_video)
1281  avcodec_flush_buffers(pCodecCtx);
1282 
1283  // Reset previous audio location to zero
1284  previous_packet_location.frame = -1;
1285  previous_packet_location.sample_start = 0;
1286 
1287  // init seek flags
1288  is_seeking = true;
1289  if (seek_count == 1) {
1290  // Don't redefine this on multiple seek attempts for a specific frame
1291  seeking_pts = seek_target;
1292  seeking_frame = requested_frame;
1293  }
1294  seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek
1295  seek_video_frame_found = 0; // used to detect which frames to throw away after a seek
1296 
1297  }
1298  else
1299  {
1300  // seek failed
1301  is_seeking = false;
1302  seeking_pts = 0;
1303  seeking_frame = 0;
1304 
1305  // dislable seeking for this reader (since it failed)
1306  // TODO: Find a safer way to do this... not sure how common it is for a seek to fail.
1307  enable_seek = false;
1308 
1309  // Close and re-open file (basically seeking to frame 1)
1310  Close();
1311  Open();
1312  }
1313  }
1314 }
1315 
1316 // Get the PTS for the current video packet
1317 long int FFmpegReader::GetVideoPTS()
1318 {
1319  int current_pts = 0;
1320  if(packet->dts != AV_NOPTS_VALUE)
1321  current_pts = packet->dts;
1322 
1323  // Return adjusted PTS
1324  return current_pts;
1325 }
1326 
1327 // Update PTS Offset (if any)
1328 void FFmpegReader::UpdatePTSOffset(bool is_video)
1329 {
1330  // Determine the offset between the PTS and Frame number (only for 1st frame)
1331  if (is_video)
1332  {
1333  // VIDEO PACKET
1334  if (video_pts_offset == 99999) // Has the offset been set yet?
1335  // Find the difference between PTS and frame number
1336  video_pts_offset = 0 - GetVideoPTS();
1337  }
1338  else
1339  {
1340  // AUDIO PACKET
1341  if (audio_pts_offset == 99999) // Has the offset been set yet?
1342  // Find the difference between PTS and frame number
1343  audio_pts_offset = 0 - packet->pts;
1344  }
1345 }
1346 
1347 // Convert PTS into Frame Number
1348 long int FFmpegReader::ConvertVideoPTStoFrame(long int pts)
1349 {
1350  // Apply PTS offset
1351  pts = pts + video_pts_offset;
1352  long int previous_video_frame = current_video_frame;
1353 
1354  // Get the video packet start time (in seconds)
1355  double video_seconds = double(pts) * info.video_timebase.ToDouble();
1356 
1357  // Divide by the video timebase, to get the video frame number (frame # is decimal at this point)
1358  long int frame = round(video_seconds * info.fps.ToDouble()) + 1;
1359 
1360  // Keep track of the expected video frame #
1361  if (current_video_frame == 0)
1362  current_video_frame = frame;
1363  else {
1364 
1365  // Sometimes frames are duplicated due to identical (or similar) timestamps
1366  if (frame == previous_video_frame) {
1367  duplicate_video_frames.insert(pair<int,int>(frame, frame));
1368 
1369  // return -1 frame number
1370  frame = -1;
1371  }
1372  else
1373  // Increment expected frame
1374  current_video_frame++;
1375 
1376  if (current_video_frame < frame)
1377  // has missing frames
1378  AppendDebugMethod("FFmpegReader::ConvertVideoPTStoFrame (detected missing frame)", "calculated frame", frame, "previous_video_frame", previous_video_frame, "current_video_frame", current_video_frame, "", -1, "", -1, "", -1);
1379 
1380  // Sometimes frames are missing due to varying timestamps, or they were dropped. Determine
1381  // if we are missing a video frame.
1382  while (current_video_frame < frame) {
1383  if (!missing_video_frames.count(current_video_frame))
1384  missing_video_frames.insert(pair<int, int>(previous_video_frame, current_video_frame));
1385 
1386  // Mark this reader as containing missing frames
1387  has_missing_frames = true;
1388 
1389  // Increment current frame
1390  current_video_frame++;
1391  }
1392  }
1393 
1394  // Return frame #
1395  return frame;
1396 }
1397 
1398 // Convert Frame Number into Video PTS
1399 long int FFmpegReader::ConvertFrameToVideoPTS(long int frame_number)
1400 {
1401  // Get timestamp of this frame (in seconds)
1402  double seconds = double(frame_number) / info.fps.ToDouble();
1403 
1404  // Calculate the # of video packets in this timestamp
1405  long int video_pts = round(seconds / info.video_timebase.ToDouble());
1406 
1407  // Apply PTS offset (opposite)
1408  return video_pts - video_pts_offset;
1409 }
1410 
1411 // Convert Frame Number into Video PTS
1412 long int FFmpegReader::ConvertFrameToAudioPTS(long int frame_number)
1413 {
1414  // Get timestamp of this frame (in seconds)
1415  double seconds = double(frame_number) / info.fps.ToDouble();
1416 
1417  // Calculate the # of audio packets in this timestamp
1418  long int audio_pts = round(seconds / info.audio_timebase.ToDouble());
1419 
1420  // Apply PTS offset (opposite)
1421  return audio_pts - audio_pts_offset;
1422 }
1423 
1424 // Calculate Starting video frame and sample # for an audio PTS
1425 AudioLocation FFmpegReader::GetAudioPTSLocation(long int pts)
1426 {
1427  // Apply PTS offset
1428  pts = pts + audio_pts_offset;
1429 
1430  // Get the audio packet start time (in seconds)
1431  double audio_seconds = double(pts) * info.audio_timebase.ToDouble();
1432 
1433  // Divide by the video timebase, to get the video frame number (frame # is decimal at this point)
1434  double frame = (audio_seconds * info.fps.ToDouble()) + 1;
1435 
1436  // Frame # as a whole number (no more decimals)
1437  int whole_frame = int(frame);
1438 
1439  // Remove the whole number, and only get the decimal of the frame
1440  double sample_start_percentage = frame - double(whole_frame);
1441 
1442  // Get Samples per frame
1443  int samples_per_frame = Frame::GetSamplesPerFrame(whole_frame, info.fps, info.sample_rate, info.channels);
1444 
1445  // Calculate the sample # to start on
1446  int sample_start = round(double(samples_per_frame) * sample_start_percentage);
1447 
1448  // Protect against broken (i.e. negative) timestamps
1449  if (whole_frame < 1)
1450  whole_frame = 1;
1451  if (sample_start < 0)
1452  sample_start = 0;
1453 
1454  // Prepare final audio packet location
1455  AudioLocation location = {whole_frame, sample_start};
1456 
1457  // Compare to previous audio packet (and fix small gaps due to varying PTS timestamps)
1458  if (previous_packet_location.frame != -1 && location.is_near(previous_packet_location, samples_per_frame, samples_per_frame))
1459  {
1460  int orig_frame = location.frame;
1461  int orig_start = location.sample_start;
1462 
1463  // Update sample start, to prevent gaps in audio
1464  if (previous_packet_location.sample_start <= samples_per_frame)
1465  {
1466  location.sample_start = previous_packet_location.sample_start;
1467  location.frame = previous_packet_location.frame;
1468  }
1469  else
1470  {
1471  // set to next frame (since we exceeded the # of samples on a frame)
1472  location.sample_start = 0;
1473  location.frame++;
1474  }
1475 
1476  // Debug output
1477  AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (Audio Gap Detected)", "Source Frame", orig_frame, "Source Audio Sample", orig_start, "Target Frame", location.frame, "Target Audio Sample", location.sample_start, "pts", pts, "", -1);
1478 
1479  }
1480 
1481  // Set previous location
1482  previous_packet_location = location;
1483 
1484  // Return the associated video frame and starting sample #
1485  return location;
1486 }
1487 
1488 // Create a new Frame (or return an existing one) and add it to the working queue.
1489 tr1::shared_ptr<Frame> FFmpegReader::CreateFrame(long int requested_frame)
1490 {
1491  // Check working cache
1492  tr1::shared_ptr<Frame> output = working_cache.GetFrame(requested_frame);
1493  if (!output)
1494  {
1495  // Create a new frame on the working cache
1496  output = tr1::shared_ptr<Frame>(new Frame(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels));
1497  output->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); // update pixel ratio
1498  output->ChannelsLayout(info.channel_layout); // update audio channel layout from the parent reader
1499  output->SampleRate(info.sample_rate); // update the frame's sample rate of the parent reader
1500 
1501  working_cache.Add(requested_frame, output);
1502 
1503  // Set the largest processed frame (if this is larger)
1504  if (requested_frame > largest_frame_processed)
1505  largest_frame_processed = requested_frame;
1506  }
1507 
1508  // Return new frame
1509  return output;
1510 }
1511 
1512 // Determine if frame is partial due to seek
1513 bool FFmpegReader::IsPartialFrame(long int requested_frame) {
1514 
1515  // Sometimes a seek gets partial frames, and we need to remove them
1516  bool seek_trash = false;
1517  long int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame
1518  if (seek_video_frame_found > max_seeked_frame)
1519  max_seeked_frame = seek_video_frame_found;
1520  if ((info.has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) ||
1521  (info.has_video && seek_video_frame_found && max_seeked_frame >= requested_frame))
1522  seek_trash = true;
1523 
1524  return seek_trash;
1525 }
1526 
1527 // Check if a frame is missing and attempt to replace it's frame image (and
1528 bool FFmpegReader::CheckMissingFrame(long int requested_frame)
1529 {
1530  // Debug output
1531  AppendDebugMethod("FFmpegReader::CheckMissingFrame", "requested_frame", requested_frame, "has_missing_frames", has_missing_frames, "missing_video_frames.size()", missing_video_frames.size(), "", -1, "", -1, "", -1);
1532 
1533  // Determine if frames are missing (due to no more video packets)
1534  if (info.has_video && !is_seeking && num_packets_since_video_frame > 60)
1535  {
1536  deque<long int>::iterator oldest_video_frame;
1537  deque<long int> frame_numbers = working_cache.GetFrameNumbers();
1538 
1539  for(oldest_video_frame = frame_numbers.begin(); oldest_video_frame != frame_numbers.end(); ++oldest_video_frame)
1540  {
1541  tr1::shared_ptr<Frame> f(working_cache.GetFrame(*oldest_video_frame));
1542 
1543  // Only add if not already in the working cache or if missing image
1544  if ((f == NULL) || (f != NULL && !f->has_image_data))
1545  if (!missing_video_frames.count(*oldest_video_frame))
1546  missing_video_frames.insert(pair<int, int>(current_video_frame, *oldest_video_frame));
1547 
1548  // Mark this reader as containing missing frames
1549  has_missing_frames = true;
1550 
1551  // Update current video frame
1552  current_video_frame = *oldest_video_frame;
1553  }
1554  }
1555 
1556  // Missing frames (sometimes frame #'s are skipped due to invalid or missing timestamps)
1557  map<long int, long int>::iterator itr;
1558  bool found_missing_frame = false;
1559  for(itr = missing_video_frames.begin(); itr != missing_video_frames.end(); ++itr)
1560  {
1561  // Create missing frame (and copy image from previous frame)
1562  tr1::shared_ptr<Frame> missing_frame = CreateFrame(itr->second);
1563  if (last_video_frame != NULL && missing_frame != NULL) {
1564  missing_frame->AddImage(tr1::shared_ptr<QImage>(new QImage(*last_video_frame->GetImage())), true);
1565 
1566  // Add this frame to the processed map (since it's already done)
1567  {
1568  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1569  processed_video_frames[itr->second] = itr->second;
1570  }
1571 
1572  // Remove missing frame from map
1573  missing_video_frames.erase(itr);
1574 
1575  // Break this loop
1576  found_missing_frame = true;
1577  }
1578  }
1579 
1580  return found_missing_frame;
1581 }
1582 
1583 // Check the working queue, and move finished frames to the finished queue
1584 void FFmpegReader::CheckWorkingFrames(bool end_of_stream, long int requested_frame)
1585 {
1586  // Loop through all working queue frames
1587  while (true)
1588  {
1589  // Get the front frame of working cache
1590  tr1::shared_ptr<Frame> f(working_cache.GetSmallestFrame());
1591 
1592  // Was a frame found?
1593  if (!f)
1594  // No frames found
1595  break;
1596 
1597  // Increment # of checks since last 'final' frame
1598  num_checks_since_final++;
1599 
1600  bool is_video_ready = false;
1601  bool is_audio_ready = false;
1602  { // limit scope of next few lines
1603  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1604  is_video_ready = processed_video_frames.count(f->number);
1605  is_audio_ready = processed_audio_frames.count(f->number);
1606  }
1607 
1608  if (previous_packet_location.frame == f->number && !end_of_stream)
1609  is_audio_ready = false; // don't finalize the last processed audio frame
1610  bool is_seek_trash = IsPartialFrame(f->number);
1611 
1612  // Adjust for available streams
1613  if (!info.has_video) is_video_ready = true;
1614  if (!info.has_audio) is_audio_ready = true;
1615 
1616  // Make final any frames that get stuck (for whatever reason)
1617  if (num_checks_since_final > 90 && (!is_video_ready || !is_audio_ready)) {
1618  if (info.has_video && !is_video_ready && last_video_frame != NULL) {
1619  // Copy image from last frame
1620  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1621  f->AddImage(tr1::shared_ptr<QImage>(new QImage(*last_video_frame->GetImage())), true);
1622  processed_video_frames[f->number] = f->number;
1623  }
1624 
1625  if (info.has_audio && !is_audio_ready) {
1626  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1627  // Mark audio as processed, and indicate the frame has audio data
1628  processed_audio_frames[f->number] = f->number;
1629  f->has_audio_data = true;
1630  }
1631 
1632  // Skip to next iteration
1633  continue;
1634  }
1635 
1636  // Debug output
1637  AppendDebugMethod("FFmpegReader::CheckWorkingFrames", "frame_number", f->number, "is_video_ready", is_video_ready, "is_audio_ready", is_audio_ready, "", -1, "", -1, "", -1);
1638 
1639  // Check if working frame is final
1640  if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash)
1641  {
1642  // Debug output
1643  AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)", "f->number", f->number, "is_seek_trash", is_seek_trash, "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "", -1, "", -1);
1644 
1645  if (!is_seek_trash)
1646  {
1647  // Reset counter since last 'final' frame
1648  num_checks_since_final = 0;
1649 
1650  // Move frame to final cache
1651  final_cache.Add(f->number, f);
1652 
1653  // Remove frame from working cache
1654  working_cache.Remove(f->number);
1655 
1656  // Update last frame processed
1657  last_frame = f->number;
1658 
1659  } else {
1660  // Seek trash, so delete the frame from the working cache, and never add it to the final cache.
1661  working_cache.Remove(f->number);
1662  }
1663  }
1664  else
1665  // Stop looping
1666  break;
1667  }
1668 }
1669 
1670 // Check for the correct frames per second (FPS) value by scanning the 1st few seconds of video packets.
1671 void FFmpegReader::CheckFPS()
1672 {
1673  check_fps = true;
1674  avpicture_alloc(pFrame, pCodecCtx->pix_fmt, info.width, info.height);
1675 
1676  int first_second_counter = 0;
1677  int second_second_counter = 0;
1678  int third_second_counter = 0;
1679  int forth_second_counter = 0;
1680  int fifth_second_counter = 0;
1681 
1682  int iterations = 0;
1683  int threshold = 500;
1684 
1685  // Loop through the stream
1686  while (true)
1687  {
1688  // Get the next packet (if any)
1689  if (GetNextPacket() < 0)
1690  // Break loop when no more packets found
1691  break;
1692 
1693  // Video packet
1694  if (packet->stream_index == videoStream)
1695  {
1696  // Check if the AVFrame is finished and set it
1697  if (GetAVFrame())
1698  {
1699  // Update PTS / Frame Offset (if any)
1700  UpdatePTSOffset(true);
1701 
1702  // Get PTS of this packet
1703  long int pts = GetVideoPTS();
1704 
1705  // Remove pFrame
1706  RemoveAVFrame(pFrame);
1707 
1708  // remove packet
1709  RemoveAVPacket(packet);
1710 
1711  // Apply PTS offset
1712  pts += video_pts_offset;
1713 
1714  // Get the video packet start time (in seconds)
1715  double video_seconds = double(pts) * info.video_timebase.ToDouble();
1716 
1717  // Increment the correct counter
1718  if (video_seconds <= 1.0)
1719  first_second_counter++;
1720  else if (video_seconds > 1.0 && video_seconds <= 2.0)
1721  second_second_counter++;
1722  else if (video_seconds > 2.0 && video_seconds <= 3.0)
1723  third_second_counter++;
1724  else if (video_seconds > 3.0 && video_seconds <= 4.0)
1725  forth_second_counter++;
1726  else if (video_seconds > 4.0 && video_seconds <= 5.0)
1727  fifth_second_counter++;
1728  else
1729  // Too far
1730  break;
1731  }
1732  else
1733  // remove packet
1734  RemoveAVPacket(packet);
1735  }
1736  else
1737  // remove packet
1738  RemoveAVPacket(packet);
1739 
1740  // Increment counters
1741  iterations++;
1742 
1743  // Give up (if threshold exceeded)
1744  if (iterations > threshold)
1745  break;
1746  }
1747 
1748  // Double check that all counters have greater than zero (or give up)
1749  if (second_second_counter == 0 || third_second_counter == 0 || forth_second_counter == 0 || fifth_second_counter == 0)
1750  {
1751  // Seek to frame 1
1752  Seek(1);
1753 
1754  // exit with no changes to FPS (not enough data to calculate)
1755  return;
1756  }
1757 
1758  int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
1759  int avg_fps = round(sum_fps / 4.0f);
1760 
1761  // Sometimes the FPS is incorrectly detected by FFmpeg. If the 1st and 2nd seconds counters
1762  // agree with each other, we are going to adjust the FPS of this reader instance. Otherwise, print
1763  // a warning message.
1764 
1765  // Get diff from actual frame rate
1766  double fps = info.fps.ToDouble();
1767  double diff = fps - double(avg_fps);
1768 
1769  // Is difference bigger than 1 frame?
1770  if (diff <= -1 || diff >= 1)
1771  {
1772  // Compare to half the frame rate (the most common type of issue)
1773  double half_fps = Fraction(info.fps.num / 2, info.fps.den).ToDouble();
1774  diff = half_fps - double(avg_fps);
1775 
1776  // Is difference bigger than 1 frame?
1777  if (diff <= -1 || diff >= 1)
1778  {
1779  // Update FPS for this reader instance
1780  info.fps = Fraction(avg_fps, 1);
1781  }
1782  else
1783  {
1784  // Update FPS for this reader instance (to 1/2 the original framerate)
1785  info.fps = Fraction(info.fps.num / 2, info.fps.den);
1786  }
1787  }
1788 
1789  // Seek to frame 1
1790  Seek(1);
1791 }
1792 
1793 // Remove AVFrame from cache (and deallocate it's memory)
1794 void FFmpegReader::RemoveAVFrame(AVPicture* remove_frame)
1795 {
1796  #pragma omp critical (packet_cache)
1797  {
1798  // Remove pFrame (if exists)
1799  if (frames.count(remove_frame))
1800  {
1801  // Free memory
1802  avpicture_free(frames[remove_frame]);
1803 
1804  // Remove from cache
1805  frames.erase(remove_frame);
1806 
1807  // Delete the object
1808  delete remove_frame;
1809  }
1810 
1811  } // end omp critical
1812 }
1813 
1814 // Remove AVPacket from cache (and deallocate it's memory)
1815 void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet)
1816 {
1817  #pragma omp critical (packet_cache)
1818  {
1819  // Remove packet (if any)
1820  if (packets.count(remove_packet))
1821  {
1822  // deallocate memory for packet
1823  av_free_packet(remove_packet);
1824 
1825  // Remove from cache
1826  packets.erase(remove_packet);
1827 
1828  // Delete the object
1829  delete remove_packet;
1830  }
1831 
1832  } // end omp critical
1833 }
1834 
1835 /// Get the smallest video frame that is still being processed
1836 long int FFmpegReader::GetSmallestVideoFrame()
1837 {
1838  // Loop through frame numbers
1839  map<long int, long int>::iterator itr;
1840  int smallest_frame = -1;
1841  for(itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr)
1842  {
1843  if (itr->first < smallest_frame || smallest_frame == -1)
1844  smallest_frame = itr->first;
1845  }
1846 
1847  // Return frame number
1848  return smallest_frame;
1849 }
1850 
1851 /// Get the smallest audio frame that is still being processed
1852 long int FFmpegReader::GetSmallestAudioFrame()
1853 {
1854  // Loop through frame numbers
1855  map<long int, long int>::iterator itr;
1856  int smallest_frame = -1;
1857  const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1858  for(itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr)
1859  {
1860  if (itr->first < smallest_frame || smallest_frame == -1)
1861  smallest_frame = itr->first;
1862  }
1863 
1864  // Return frame number
1865  return smallest_frame;
1866 }
1867 
1868 // Generate JSON string of this object
1870 
1871  // Return formatted string
1872  return JsonValue().toStyledString();
1873 }
1874 
1875 // Generate Json::JsonValue for this object
1877 
1878  // Create root json object
1879  Json::Value root = ReaderBase::JsonValue(); // get parent properties
1880  root["type"] = "FFmpegReader";
1881  root["path"] = path;
1882 
1883  // return JsonValue
1884  return root;
1885 }
1886 
1887 // Load JSON string into this object
1888 void FFmpegReader::SetJson(string value) throw(InvalidJSON) {
1889 
1890  // Parse JSON string into JSON objects
1891  Json::Value root;
1892  Json::Reader reader;
1893  bool success = reader.parse( value, root );
1894  if (!success)
1895  // Raise exception
1896  throw InvalidJSON("JSON could not be parsed (or is invalid)", "");
1897 
1898  try
1899  {
1900  // Set all values that match
1901  SetJsonValue(root);
1902  }
1903  catch (exception e)
1904  {
1905  // Error parsing JSON (or missing keys)
1906  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", "");
1907  }
1908 }
1909 
1910 // Load Json::JsonValue into this object
1911 void FFmpegReader::SetJsonValue(Json::Value root) throw(InvalidFile) {
1912 
1913  // Set parent data
1915 
1916  // Set data from Json (if key is found)
1917  if (!root["path"].isNull())
1918  path = root["path"].asString();
1919 
1920  // Re-Open path, and re-init everything (if needed)
1921  if (is_open)
1922  {
1923  Close();
1924  Open();
1925  }
1926 }
#define AV_RESET_FRAME(av_frame)
long long file_size
Size of file (in bytes)
Definition: ReaderBase.h:65
tr1::shared_ptr< Frame > GetFrame(long int requested_frame)
#define AV_FREE_FRAME(av_frame)
int num
Numerator for the fraction.
Definition: Fraction.h:44
void Add(long int frame_number, tr1::shared_ptr< Frame > frame)
Add a Frame to the cache.
Definition: Cache.cpp:57
CriticalSection processingCriticalSection
Definition: ReaderBase.h:100
ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition: ReaderBase.h:83
int width
The width of the video (in pixesl)
Definition: ReaderBase.h:67
void Remove(long int frame_number)
Remove a specific frame.
Definition: Cache.cpp:154
This class represents a single frame of video (i.e. image & audio data)
Definition: Frame.h:114
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:41
float duration
Length of time (in seconds)
Definition: ReaderBase.h:64
string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: ReaderBase.h:79
#define AVCODEC_MAX_AUDIO_FRAME_SIZE
#define OPEN_MP_NUM_PROCESSORS
deque< long int > GetFrameNumbers()
Return a deque of all frame numbers in this queue (returns just a copy of the data) ...
Definition: Cache.cpp:95
string Json()
Get and Set JSON methods.
Json::Value JsonValue()
Generate Json::JsonValue for this object.
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:234
bool has_video
Determines if this file has a video stream.
Definition: ReaderBase.h:61
void Close()
Close File.
Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3) ...
Definition: ReaderBase.h:72
FFmpegReader(string path)
void SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels)
Set maximum bytes to a different amount based on a ReaderInfo struct.
Definition: Cache.cpp:256
int audio_bit_rate
The bit rate of the audio stream (in bytes)
Definition: ReaderBase.h:80
bool has_audio
Determines if this file has an audio stream.
Definition: ReaderBase.h:62
void AppendDebugMethod(string method_name, string arg1_name, float arg1_value, string arg2_name, float arg2_value, string arg3_name, float arg3_value, string arg4_name, float arg4_value, string arg5_name, float arg5_value, string arg6_name, float arg6_value)
Append debug information as JSON.
Definition: ReaderBase.cpp:67
Exception when no valid codec is found for a file.
Definition: Exceptions.h:122
int audio_stream_index
The index of the audio stream.
Definition: ReaderBase.h:84
Exception when no streams are found in the file.
Definition: Exceptions.h:192
int height
The height of the video (in pixels)
Definition: ReaderBase.h:66
void SetJson(string value)
Load JSON string into this object.
#define AV_ALLOCATE_FRAME()
Exception for files that can not be found or opened.
Definition: Exceptions.h:132
This class represents a fraction.
Definition: Fraction.h:42
Cache final_cache
Final cache object used to hold final frames.
Definition: FFmpegReader.h:231
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround...
tr1::shared_ptr< Frame > GetSmallestFrame()
Get the smallest frame number.
Definition: Cache.cpp:112
virtual Json::Value JsonValue()=0
Generate Json::JsonValue for this object.
Definition: ReaderBase.cpp:153
#define PixelFormat
virtual void SetJsonValue(Json::Value root)=0
Load Json::JsonValue into this object.
Definition: ReaderBase.cpp:202
ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:120
Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:69
Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: ReaderBase.h:76
Exception for frames that are out of bounds.
Definition: Exceptions.h:202
int is_near(AudioLocation location, int samples_per_frame, int amount)
Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
Definition: ReaderBase.h:71
tr1::shared_ptr< Frame > GetFrame(long int frame_number)
Get a frame from the cache.
Definition: Cache.cpp:79
void Clear()
Clear the cache of all frames.
Definition: Cache.cpp:202
Exception for invalid JSON.
Definition: Exceptions.h:152
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition: ReaderBase.h:68
This struct holds the associated video frame and starting sample # for an audio packet.
Definition: FFmpegReader.h:59
void Open()
Open File - which is called by the constructor automatically.
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: ReaderBase.h:70
#define PIX_FMT_RGBA
Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
Definition: ReaderBase.h:85
string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: ReaderBase.h:73
~FFmpegReader()
Destructor.
int den
Denominator for the fraction.
Definition: Fraction.h:45
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:82
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
int video_stream_index
The index of the video stream.
Definition: ReaderBase.h:75
long int video_length
The number of frames in the video stream.
Definition: ReaderBase.h:74
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:482
long int Count()
Count the frames in the queue.
Definition: Cache.cpp:212
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:46
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:81
Exception when too many seek attempts happen.
Definition: Exceptions.h:254