Exemple #1
0
int main (int argc, char **argv)
{
  fas_error_type video_error;
  fas_context_ref_type context;
  fas_raw_image_type image_buffer;
  
  if (argc < 2) {
    fprintf (stderr, "usage: %s <video_file>\n", argv[0]);
    return -1;
  }

  fas_initialize (FAS_FALSE, FAS_RGB24);
  
  video_error = fas_open_video (&context, argv[1]);
  if (video_error != FAS_SUCCESS)
    return -1;

  while (fas_frame_available (context))
    {
      if (FAS_SUCCESS != fas_get_frame (context, &image_buffer))
	return -1;
      fas_free_frame (image_buffer);

      video_error = fas_step_forward (context);
    }

  seek_table_type table;
  table = fas_get_seek_table(context);

  seek_show_raw_table(stdout, table);
  
  return 1;
}
Exemple #2
0
/* fas_seek_to_frame */
fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index)
{

  fas_error_type fas_error;

  if ((NULL == context) || (FAS_FALSE == context->is_video_active))
    return private_show_error("invalid or unopened context", FAS_INVALID_ARGUMENT);

  //  printf("seeking to %d (from %d)!\n", target_index, context->current_frame_index);
  if (target_index == context->current_frame_index)
    return FAS_SUCCESS;

  fas_error = fas_seek_to_nearest_key (context, target_index);

  if (fas_error != FAS_SUCCESS)
    return private_show_error("error advancing to key frame before seek", fas_error);

  if (fas_get_frame_index(context) > target_index)
    return private_show_error("error advancing to key frame before seek (index isn't right)", fas_error);

  while (fas_get_frame_index(context) < target_index)
    {
      if (fas_frame_available(context))
	fas_step_forward(context);
      else
	return private_show_error("error advancing to request frame (probably out of range)", FAS_SEEK_ERROR);
    }


  return FAS_SUCCESS;
}
Exemple #3
0
/* private_complete_seek_table */
fas_error_type private_complete_seek_table (fas_context_ref_type context)
{
  fas_error_type fas_error;

  if ((NULL == context) || (FAS_FALSE == context->is_video_active))
    return private_show_error("invalid or unopened context", FAS_INVALID_ARGUMENT);

  if (context->seek_table.completed)
    return FAS_SUCCESS;

  fas_error = fas_seek_to_nearest_key(context, context->seek_table.num_frames + FIRST_FRAME_INDEX - 1);
  if (FAS_SUCCESS != fas_error)
    return private_show_error("failed when trying to complete seek table (1) (first frame not labeled keyframe?)", fas_error);

  while (fas_frame_available(context))
    {
      //      printf("%d\n", context->seek_table.num_frames);
      fas_step_forward(context);
    }

  if (!context->seek_table.completed)
    return private_show_error("failed when trying to complete seek table (2)", FAS_SEEK_ERROR);

  return FAS_SUCCESS;
}
Exemple #4
0
/* private_seek_to_nearest_key */
fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset)
{
  fas_error_type fas_error;
  seek_entry_type seek_entry;
  seek_error_type seek_error;
  int flags = 0;

  if ((NULL == context) || (FAS_TRUE != context->is_video_active))
    return private_show_error("invalid or unopened context", FAS_INVALID_ARGUMENT);

#ifdef _DEBUG
  printf("HERE: from: %d to: %d offset: %d\n", context->current_frame_index, target_index, offset);
#endif
  seek_error = seek_get_nearest_entry(&(context->seek_table), &seek_entry, target_index, offset);

  if (seek_error != seek_no_error)
    return private_show_error("error while searching seek table", FAS_SEEK_ERROR);

  if (seek_entry.display_index == context->current_frame_index)
    return FAS_SUCCESS;

#ifdef _DEBUG
  printf("HERE: from: %d to: %d (%d) offset: %d\n", context->current_frame_index, target_index, seek_entry.display_index, offset);
  printf("trying to seek to %d (%lld->%lld)\n", seek_entry.display_index, seek_entry.first_packet_dts, seek_entry.last_packet_dts);
#endif

  // if something goes terribly wrong, return bad current_frame_index
  context->current_frame_index = -2;
  context->is_frame_available = FAS_TRUE;

  if (seek_entry.first_packet_dts <= context->current_dts)
    flags = AVSEEK_FLAG_BACKWARD;

  //  printf("av_seek_frame: %lld\n", seek_entry.first_packet_dts);
  if (av_seek_frame(context->format_context, context->stream_idx, seek_entry.first_packet_dts, flags) < 0)
    return private_show_error("seek to keyframe failed", FAS_SEEK_ERROR);

  avcodec_flush_buffers (context->codec_context);

  fas_error = fas_step_forward (context);

  if (fas_error != FAS_SUCCESS || !context->is_frame_available)
  {
    // something bad has happened, try previous keyframe
    private_show_warning("processing of seeked keyframe failed, trying previous keyframe");
    return private_seek_to_nearest_key(context, target_index, offset + 1);
  }

  while (context->current_dts < seek_entry.last_packet_dts)
  {
#ifdef _DEBUG
    printf("frame-times: current: %lld target: %lld is_key: %d\n", context->current_dts, seek_entry.last_packet_dts, context->frame_buffer->key_frame);
#endif
    fas_error = fas_step_forward(context);
    if (fas_error != FAS_SUCCESS)
      return private_show_error("unable to process up to target frame (fas_seek_to_frame)", fas_error);
  }

#ifdef _DEBUG
  printf("keyframe vitals: %d looking_for: %lld at: %lld\n", seek_entry.display_index, seek_entry.last_packet_dts, context->current_dts);
#endif
  if (context->current_dts != seek_entry.last_packet_dts)
  {
    /* seek to last key-frame, but look for this one */
    private_show_warning("missed keyframe, trying previous keyframe");
    return private_seek_to_nearest_key(context, target_index, offset + 1);
  }

  /**
   * Ideally, we could just check if the frame decoded is of the correct time
   * stamp, but we need several ugly workarounds:
   *
   * 1) Some videos have bad keyframes that don't get decoded properly. In this
   *    cases, we need to go back a keyframe.
   *
   * 2) Other times, none of the frames are labeled keyframes. In these cases,
   *    we need to allow seeking to frame 0 even when it's not labeled as a
   *    keyframe. Messy set of conditions.
   */

  if ((!context->frame_buffer->key_frame) && (seek_entry.display_index != 0))
  {
    private_show_warning("found keyframe, but not labeled as keyframe, so trying previous keyframe.");
    /* seek & look for previous keyframe */
    /* REMOVE FROM TABLE?                */
    return private_seek_to_nearest_key(context, seek_entry.display_index - 1, 0);
  }

  context->current_frame_index = seek_entry.display_index;

  return FAS_SUCCESS;
}
Exemple #5
0
/* fas_open_video */
fas_error_type fas_open_video (fas_context_ref_type *context_ptr, const char *file_path)
{
  int stream_idx;
  int numBytes;
  fas_context_ref_type fas_context;
  AVCodec *codec;

  if (NULL == context_ptr)
    return private_show_error("NULL context pointer provided", FAS_INVALID_ARGUMENT);

  *context_ptr = NULL; // set returned context to NULL in case of error

  fas_context = (fas_context_ref_type) malloc(sizeof(fas_context_type));
  memset(fas_context, 0, sizeof(fas_context_type));

  if (NULL == fas_context)
    return private_show_error("unable to allocate buffer", FAS_OUT_OF_MEMORY);

  fas_context->is_video_active        = FAS_TRUE;
  fas_context->is_frame_available     = FAS_TRUE;
  fas_context->current_frame_index    = FIRST_FRAME_INDEX - 1;
  fas_context->current_dts            = AV_NOPTS_VALUE;
  fas_context->previous_dts           = AV_NOPTS_VALUE;
  fas_context->keyframe_packet_dts    = AV_NOPTS_VALUE;
  fas_context->first_dts              = AV_NOPTS_VALUE;
  fas_context->seek_table = seek_init_table(-1); /* default starting size */

  if (av_open_input_file(&(fas_context->format_context), file_path, NULL, 0, NULL ) != 0)
  {
    fas_close_video(fas_context);
    return private_show_error("failure to open file", FAS_UNSUPPORTED_FORMAT);
  }

  if (av_find_stream_info (fas_context->format_context) < 0)
  {
    fas_close_video(fas_context);
    return private_show_error("could not extract stream information", FAS_UNSUPPORTED_FORMAT);
  }

  if (SHOW_WARNING_MESSAGES)
    av_dump_format(fas_context->format_context, 0, file_path, 0);

  for (stream_idx = 0; stream_idx < fas_context->format_context->nb_streams; stream_idx++)
  {
    if (fas_context->format_context->streams[stream_idx]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
    {
      fas_context->stream_idx = stream_idx;
      fas_context->codec_context  = fas_context->format_context->streams[stream_idx]->codec;
      break;
    }
  }

  if (fas_context->codec_context == 0)
  {
    fas_close_video(fas_context);
    return private_show_error("failure to find a video stream", FAS_UNSUPPORTED_FORMAT);
  }

  codec = avcodec_find_decoder(fas_context->codec_context->codec_id);

  if (!codec)
  {
    fas_context->codec_context = 0;
    fas_close_video(fas_context);
    return private_show_error("failed to find correct video codec", FAS_UNSUPPORTED_CODEC);
  }

  if (avcodec_open(fas_context->codec_context, codec) < 0)
  {
    fas_context->codec_context = 0;
    fas_close_video(fas_context);
    return private_show_error("failed to open codec", FAS_UNSUPPORTED_CODEC);
  }

  fas_context->frame_buffer = avcodec_alloc_frame();
  if (fas_context->frame_buffer == NULL)
  {
    fas_close_video(fas_context);
    return private_show_error("failed to allocate frame buffer", FAS_OUT_OF_MEMORY);
  }

  fas_context->rgb_frame_buffer = avcodec_alloc_frame();
  if (fas_context->rgb_frame_buffer == NULL)
  {
    fas_close_video(fas_context);
    return private_show_error("failed to allocate rgb frame buffer", FAS_OUT_OF_MEMORY);
  }
  numBytes = avpicture_get_size(PIX_FMT_RGB24, fas_context->codec_context->width, fas_context->codec_context->height);
  fas_context->rgb_buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
  avpicture_fill((AVPicture *)fas_context->rgb_frame_buffer, fas_context->rgb_buffer, PIX_FMT_RGB24, fas_context->codec_context->width, fas_context->codec_context->height);

  fas_context->gray8_frame_buffer = avcodec_alloc_frame();
  if (fas_context->gray8_frame_buffer == NULL)
  {
    fas_close_video(fas_context);
    return private_show_error("failed to allocate gray8 frame buffer", FAS_OUT_OF_MEMORY);
  }

  fas_context->rgb_buffer = 0;
  fas_context->gray8_buffer = 0;
  fas_context->rgb_already_converted = FAS_FALSE;
  fas_context->gray8_already_converted = FAS_FALSE;

  *context_ptr = fas_context;

  if (FAS_SUCCESS != fas_step_forward(*context_ptr))
    return private_show_error("failure decoding first frame", FAS_NO_MORE_FRAMES);

  if (!fas_frame_available(*context_ptr))
    return private_show_error("couldn't find a first frame (no valid frames in video stream)", FAS_NO_MORE_FRAMES);

  return FAS_SUCCESS;
}
void do_random_test(fas_context_ref_type context, int start, int stop, int count)
{
  //  printf ("start: %d  stop: %d\n", start, stop );

  while (fas_get_frame_index(context) < start)
    if (FAS_SUCCESS != fas_step_forward(context))
      fail("failed on advancement\n");

  fas_raw_image_type *ref_frames = malloc( (stop - start + 1)* sizeof(fas_raw_image_type));
  
  int i;
  fas_error_type video_error;

  while (fas_get_frame_index(context) <= stop)
    {
      i = fas_get_frame_index(context) - start;

      video_error = fas_get_frame(context, &(ref_frames[i]));
      if (video_error != FAS_SUCCESS)    fail("fail on test(1)\n");

      video_error = fas_step_forward(context);
      if (video_error != FAS_SUCCESS)    fail("fail on test(2)\n");

    }

  int index = -1;
  int prev_index;

  for (i=0;i<count;i++)
    {
      int offset = random() % (stop - start + 1);
      prev_index = index;
      index = start + offset;

      video_error = fas_seek_to_frame(context, index);
      if (video_error != FAS_SUCCESS)    fail("fail on test(seek)\n");


      fas_raw_image_type test_frame;
      video_error = fas_get_frame(context, &test_frame);
      if (video_error != FAS_SUCCESS)    fail("fail on test(seek2)\n");

      //      printf("offset: %d / %d\n", offset, stop - start + 1);
      
      if (!compare_frames(test_frame, ref_frames[offset]))
	{	  
	  char buffer[70];
	  
	  sprintf(buffer, "fail-%d-test.ppm", index);
	  ppm_save(&test_frame, buffer);
	  sprintf(buffer, "fail-%d-ref.ppm", index);
	  ppm_save(&ref_frames[offset], buffer);
	  sprintf(buffer, "failed on compare after seeking (%d->%d)\n", prev_index, index);
	  
	  fail(buffer);
	}
      
      fas_free_frame(test_frame);
    }
  
  for (i=0;i<stop - start + 1;i++)
    free(ref_frames[i].data);
    
  free(ref_frames);
}