| @@ -53,6 +53,18 @@ static AVPacket pkt; | |||||
| static int video_frame_count = 0; | static int video_frame_count = 0; | ||||
| static int audio_frame_count = 0; | static int audio_frame_count = 0; | ||||
| /* The different ways of decoding and managing data memory. You are not | |||||
| * supposed to support all the modes in your application but pick the one most | |||||
| * appropriate to your needs. Look for the use of api_mode in this example to | |||||
| * see what are the differences of API usage between them */ | |||||
| enum { | |||||
| API_MODE_OLD = 0, /* old method, deprecated */ | |||||
| API_MODE_NEW_API_REF_COUNT = 1, /* new method, using the frame reference counting */ | |||||
| API_MODE_NEW_API_NO_REF_COUNT = 2, /* new method, without reference counting */ | |||||
| }; | |||||
| static int api_mode = API_MODE_OLD; | |||||
| static int decode_packet(int *got_frame, int cached) | static int decode_packet(int *got_frame, int cached) | ||||
| { | { | ||||
| int ret = 0; | int ret = 0; | ||||
| @@ -115,6 +127,11 @@ static int decode_packet(int *got_frame, int cached) | |||||
| } | } | ||||
| } | } | ||||
| /* If we use the new API with reference counting, we own the data and need | |||||
| * to de-reference it when we don't use it anymore */ | |||||
| if (*got_frame && api_mode == API_MODE_NEW_API_REF_COUNT) | |||||
| av_frame_unref(frame); | |||||
| return decoded; | return decoded; | ||||
| } | } | ||||
| @@ -125,6 +142,7 @@ static int open_codec_context(int *stream_idx, | |||||
| AVStream *st; | AVStream *st; | ||||
| AVCodecContext *dec_ctx = NULL; | AVCodecContext *dec_ctx = NULL; | ||||
| AVCodec *dec = NULL; | AVCodec *dec = NULL; | ||||
| AVDictionary *opts = NULL; | |||||
| ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); | ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); | ||||
| if (ret < 0) { | if (ret < 0) { | ||||
| @@ -144,7 +162,10 @@ static int open_codec_context(int *stream_idx, | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { | |||||
| /* Init the decoders, with or without reference counting */ | |||||
| if (api_mode == API_MODE_NEW_API_REF_COUNT) | |||||
| av_dict_set(&opts, "refcounted_frames", "1", 0); | |||||
| if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) { | |||||
| fprintf(stderr, "Failed to open %s codec\n", | fprintf(stderr, "Failed to open %s codec\n", | ||||
| av_get_media_type_string(type)); | av_get_media_type_string(type)); | ||||
| return ret; | return ret; | ||||
| @@ -187,15 +208,31 @@ int main (int argc, char **argv) | |||||
| { | { | ||||
| int ret = 0, got_frame; | int ret = 0, got_frame; | ||||
| if (argc != 4) { | |||||
| fprintf(stderr, "usage: %s input_file video_output_file audio_output_file\n" | |||||
| if (argc != 4 && argc != 5) { | |||||
| fprintf(stderr, "usage: %s [-refcount=<old|new_norefcount|new_refcount>] " | |||||
| "input_file video_output_file audio_output_file\n" | |||||
| "API example program to show how to read frames from an input file.\n" | "API example program to show how to read frames from an input file.\n" | ||||
| "This program reads frames from a file, decodes them, and writes decoded\n" | "This program reads frames from a file, decodes them, and writes decoded\n" | ||||
| "video frames to a rawvideo file named video_output_file, and decoded\n" | "video frames to a rawvideo file named video_output_file, and decoded\n" | ||||
| "audio frames to a rawaudio file named audio_output_file.\n" | |||||
| "audio frames to a rawaudio file named audio_output_file.\n\n" | |||||
| "If the -refcount option is specified, the program use the\n" | |||||
| "reference counting frame system which allows keeping a copy of\n" | |||||
| "the data for longer than one decode call. If unset, it's using\n" | |||||
| "the classic old method.\n" | |||||
| "\n", argv[0]); | "\n", argv[0]); | ||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| if (argc == 5) { | |||||
| const char *mode = argv[1] + strlen("-refcount="); | |||||
| if (!strcmp(mode, "old")) api_mode = API_MODE_OLD; | |||||
| else if (!strcmp(mode, "new_norefcount")) api_mode = API_MODE_NEW_API_NO_REF_COUNT; | |||||
| else if (!strcmp(mode, "new_refcount")) api_mode = API_MODE_NEW_API_REF_COUNT; | |||||
| else { | |||||
| fprintf(stderr, "unknow mode '%s'\n", mode); | |||||
| exit(1); | |||||
| } | |||||
| argv++; | |||||
| } | |||||
| src_filename = argv[1]; | src_filename = argv[1]; | ||||
| video_dst_filename = argv[2]; | video_dst_filename = argv[2]; | ||||
| audio_dst_filename = argv[3]; | audio_dst_filename = argv[3]; | ||||
| @@ -257,7 +294,12 @@ int main (int argc, char **argv) | |||||
| goto end; | goto end; | ||||
| } | } | ||||
| frame = avcodec_alloc_frame(); | |||||
| /* When using the new API, you need to use the libavutil/frame.h API, while | |||||
| * the classic frame management is available in libavcodec */ | |||||
| if (api_mode == API_MODE_OLD) | |||||
| frame = avcodec_alloc_frame(); | |||||
| else | |||||
| frame = av_frame_alloc(); | |||||
| if (!frame) { | if (!frame) { | ||||
| fprintf(stderr, "Could not allocate frame\n"); | fprintf(stderr, "Could not allocate frame\n"); | ||||
| ret = AVERROR(ENOMEM); | ret = AVERROR(ENOMEM); | ||||
| @@ -336,7 +378,10 @@ end: | |||||
| fclose(video_dst_file); | fclose(video_dst_file); | ||||
| if (audio_dst_file) | if (audio_dst_file) | ||||
| fclose(audio_dst_file); | fclose(audio_dst_file); | ||||
| av_free(frame); | |||||
| if (api_mode == API_MODE_OLD) | |||||
| avcodec_free_frame(&frame); | |||||
| else | |||||
| av_frame_free(&frame); | |||||
| av_free(video_dst_data[0]); | av_free(video_dst_data[0]); | ||||
| return ret < 0; | return ret < 0; | ||||