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; }
/* 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; }
/* 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; }
fas_error_type fas_get_frame(fas_context_ref_type context, fas_raw_image_type *image_ptr) { int buffer_size; fas_error_type fas_error; int j; unsigned char *from; unsigned char *to; if (NULL == context || FAS_FALSE == context->is_video_active) return private_show_error("null context or inactive video", FAS_INVALID_ARGUMENT); if (NULL == image_ptr) return private_show_error("null image_ptr on get_frame", FAS_INVALID_ARGUMENT); if (!fas_frame_available(context)) return private_show_error("no frame available for extraction", FAS_NO_MORE_FRAMES); memset (image_ptr, 0, sizeof (fas_raw_image_type)); switch (fmt) { case PIX_FMT_RGB24: image_ptr->bytes_per_line = context->codec_context->width * 3; image_ptr->color_space = FAS_RGB24; break; case PIX_FMT_BGR24: image_ptr->bytes_per_line = context->codec_context->width * 3; image_ptr->color_space = FAS_BGR24; break; case PIX_FMT_ARGB: image_ptr->bytes_per_line = context->codec_context->width * 4; image_ptr->color_space = FAS_ARGB32; break; case PIX_FMT_ABGR: image_ptr->bytes_per_line = context->codec_context->width * 4; image_ptr->color_space = FAS_ABGR32; break; case PIX_FMT_YUV420P: image_ptr->bytes_per_line = (context->codec_context->width * 3) >> 1; image_ptr->color_space = FAS_YUV420P; break; case PIX_FMT_YUYV422: image_ptr->bytes_per_line = context->codec_context->width * 2; image_ptr->color_space = FAS_YUYV422; break; case PIX_FMT_UYVY422: image_ptr->bytes_per_line = context->codec_context->width * 2; image_ptr->color_space = FAS_UYVY422; break; case PIX_FMT_YUV422P: image_ptr->bytes_per_line = context->codec_context->width * 2; image_ptr->color_space = FAS_YUV422P; break; case PIX_FMT_YUV444P: image_ptr->bytes_per_line = context->codec_context->width * 3; image_ptr->color_space = FAS_YUV444P; break; } buffer_size = image_ptr->bytes_per_line * context->codec_context->height; image_ptr->data = (unsigned char *)malloc (buffer_size); if (NULL == image_ptr->data) return private_show_error("unable to allocate space for RGB image", FAS_OUT_OF_MEMORY); image_ptr->width = context->codec_context->width; image_ptr->height = context->codec_context->height; fas_error = private_convert_to_rgb(context); for (j=0;j<context->codec_context->height; j++) { from = context->rgb_frame_buffer->data[0] + j*context->rgb_frame_buffer->linesize[0]; to = image_ptr->data + j*image_ptr->bytes_per_line; memcpy(to, from, image_ptr->bytes_per_line); } if (FAS_SUCCESS != fas_error) return private_show_error("unable to convert image to RGB", FAS_FAILURE); return FAS_SUCCESS; }
/* 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; }