Last active
March 20, 2026 12:30
-
-
Save O2C14/33897e40855e4562b44e047a021b92ce to your computer and use it in GitHub Desktop.
cmake编译最小ffmpeg8.1工程, 用于flac解码
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| file(GLOB FF_SOURCES | |
| "libavcodec/flac*.c" | |
| "libavformat/flacdec.c" | |
| "libavformat/flac_picture.c" | |
| ) | |
| add_library( | |
| ffmpeg STATIC | |
| ${FF_SOURCES} | |
| libavcodec/packet.c | |
| libavcodec/allcodecs.c | |
| libavcodec/avcodec.c | |
| libavcodec/decode.c | |
| libavutil/samplefmt.c | |
| libavcodec/parser.c | |
| libavcodec/options.c | |
| libavutil/frame.c | |
| libavutil/opt.c | |
| libavcodec/utils.c | |
| libavcodec/codec_desc.c | |
| libavutil/buffer.c | |
| libavcodec/profiles.c | |
| libavutil/crc.c | |
| # libavutil/log.c | |
| libavutil/log2_tab.c | |
| libavutil/bprint.c | |
| libavutil/mem.c | |
| libavutil/dict.c | |
| libavutil/imgutils.c | |
| libavutil/channel_layout.c | |
| libavutil/refstruct.c | |
| libavcodec/bsf.c | |
| libavutil/side_data.c | |
| libavutil/error.c | |
| libavutil/mathematics.c | |
| libavcodec/get_buffer.c | |
| libavutil/avstring.c | |
| libavcodec/encode.c | |
| libavutil/pixdesc.c | |
| libavutil/hwcontext.c | |
| libavcodec/exif.c | |
| libavutil/display.c | |
| libavcodec/tiff_common.c | |
| libavutil/eval.c | |
| libavutil/rational.c | |
| libavcodec/codec_par.c | |
| libavcodec/parsers.c | |
| libavutil/parseutils.c | |
| libavutil/reverse.c | |
| libavutil/avsscanf.c | |
| libavcodec/threadprogress.c | |
| libavcodec/bitstream_filters.c | |
| libavformat/demux.c | |
| libavformat/avformat.c | |
| libavutil/utils.c | |
| libavformat/format.c | |
| libavformat/options.c | |
| libavformat/id3v1.c | |
| libavformat/id3v2.c | |
| libavformat/aviobuf.c | |
| libavformat/metadata.c | |
| libavformat/demux_utils.c | |
| libavutil/timestamp.c | |
| libavformat/seek.c | |
| libavformat/avio.c | |
| libavcodec/raw.c | |
| libavutil/iamf.c | |
| libavformat/utils.c | |
| libavformat/allformats.c | |
| libavformat/protocols.c | |
| libavformat/rawdec.c | |
| libavformat/oggparsevorbis.c #? | |
| libavformat/vorbiscomment.c #? | |
| libavformat/replaygain.c | |
| libavutil/base64.c | |
| # libavformat/file.c # 没有posix接口就自己写 | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 实际上不止这个文件要手动创建,下面是所有要手动配置的文件 | |
| libavcodec/bsf_list.c | |
| libavcodec/codec_list.c | |
| libavcodec/parser_list.c | |
| libavformat/demuxer_list.c | |
| libavformat/muxer_list.c | |
| libavformat/protocol_list.c | |
| */ | |
| // 这是codec_list.c的例子, 按需添加. 注意这些列表的结尾要有一个NULL | |
| const FFCodec *codec_list[] = { | |
| &ff_flac_decoder, | |
| // &ff_mp3_decoder, | |
| NULL | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //参考配置 | |
| #ifndef FFMPEG_CONFIG_H | |
| #define FFMPEG_CONFIG_H | |
| #define HAVE_PRAGMA_DEPRECATED (1) | |
| #define HAVE_FAST_64BIT (1) | |
| #define HAVE_CBRT (1) | |
| #define HAVE_CBRTF (1) | |
| #define HAVE_COPYSIGN (1) | |
| #define HAVE_ERF (1) | |
| #define HAVE_HYPOT (1) | |
| #define HAVE_RINT (1) | |
| #define HAVE_LRINT (1) | |
| #define HAVE_LRINTF (1) | |
| #define HAVE_ROUND (1) | |
| #define HAVE_ROUNDF (1) | |
| #define HAVE_TRUNC (1) | |
| #define HAVE_TRUNCF (1) | |
| #define CHECKED | |
| #define HAVE_THREADS (0) | |
| #define CONFIG_GRAY (1) | |
| #define CONFIG_MEMORY_POISONING (1) | |
| #define HAVE_SIMD_ALIGN_64 (0) | |
| #define CONFIG_ZLIB (0) | |
| #define CONFIG_FILE_PROTOCOL (1) | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 注意unpadded_linesize只是一个通道的大小, 还要乘上frame->ch_layout.nb_channels | |
| /* | |
| * Copyright (c) 2012 Stefano Sabatini | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| * of this software and associated documentation files (the "Software"), to deal | |
| * in the Software without restriction, including without limitation the rights | |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| * copies of the Software, and to permit persons to whom the Software is | |
| * furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| * THE SOFTWARE. | |
| */ | |
| /** | |
| * @file libavformat and libavcodec demuxing and decoding API usage example | |
| * @example demux_decode.c | |
| * | |
| * Show how to use the libavformat and libavcodec API to demux and decode audio | |
| * and video data. Write the output as raw audio and input files to be played by | |
| * ffplay. | |
| */ | |
| #include <libavutil/imgutils.h> | |
| #include <libavutil/samplefmt.h> | |
| #include <libavutil/timestamp.h> | |
| #include <libavcodec/avcodec.h> | |
| #include <libavformat/avformat.h> | |
| static AVFormatContext *fmt_ctx = NULL; | |
| static AVCodecContext *audio_dec_ctx; | |
| static int width, height; | |
| static enum AVPixelFormat pix_fmt; | |
| static AVStream *audio_stream = NULL; | |
| static const char *src_filename = NULL; | |
| static const char *audio_dst_filename = NULL; | |
| static FILE *audio_dst_file = NULL; | |
| static int audio_stream_idx = -1; | |
| static AVFrame *frame = NULL; | |
| static AVPacket *pkt = NULL; | |
| static int audio_frame_count = 0; | |
| static int output_audio_frame(AVFrame *frame) | |
| { | |
| size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format); | |
| printf("audio_frame n:%d nb_samples:%d pts:%s\n", | |
| audio_frame_count++, frame->nb_samples, | |
| av_ts2timestr(frame->pts, &audio_dec_ctx->time_base)); | |
| /* Write the raw audio data samples of the first plane. This works | |
| * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However, | |
| * most audio decoders output planar audio, which uses a separate | |
| * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P). | |
| * In other words, this code will write only the first audio channel | |
| * in these cases. | |
| * You should use libswresample or libavfilter to convert the frame | |
| * to packed data. */ | |
| // fwrite(frame->extended_data[0], 1, unpadded_linesize, audio_dst_file); | |
| // 输出到i2s或者codec | |
| return 0; | |
| } | |
| static int decode_packet(AVCodecContext *dec, const AVPacket *pkt) | |
| { | |
| int ret = 0; | |
| // submit the packet to the decoder | |
| ret = avcodec_send_packet(dec, pkt); | |
| if (ret < 0) { | |
| fprintf(stderr, "Error submitting a packet for decoding (%s)\n", av_err2str(ret)); | |
| return ret; | |
| } | |
| // get all the available frames from the decoder | |
| while (ret >= 0) { | |
| ret = avcodec_receive_frame(dec, frame); | |
| if (ret < 0) { | |
| // those two return values are special and mean there is no output | |
| // frame available, but there were no errors during decoding | |
| if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) | |
| return 0; | |
| fprintf(stderr, "Error during decoding (%s)\n", av_err2str(ret)); | |
| return ret; | |
| } | |
| // write the frame data to output file | |
| if (dec->codec->type == AVMEDIA_TYPE_AUDIO) | |
| ret = output_audio_frame(frame); | |
| av_frame_unref(frame); | |
| } | |
| return ret; | |
| } | |
| static int open_codec_context(int *stream_idx, | |
| AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type) | |
| { | |
| int ret, stream_index; | |
| AVStream *st; | |
| const AVCodec *dec = NULL; | |
| ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); | |
| if (ret < 0) { | |
| fprintf(stderr, "Could not find %s stream in input file '%s'\n", | |
| av_get_media_type_string(type), src_filename); | |
| return ret; | |
| } else { | |
| stream_index = ret; | |
| st = fmt_ctx->streams[stream_index]; | |
| /* find decoder for the stream */ | |
| dec = avcodec_find_decoder(st->codecpar->codec_id); | |
| if (!dec) { | |
| fprintf(stderr, "Failed to find %s codec\n", | |
| av_get_media_type_string(type)); | |
| return AVERROR(EINVAL); | |
| } | |
| /* Allocate a codec context for the decoder */ | |
| *dec_ctx = avcodec_alloc_context3(dec); | |
| if (!*dec_ctx) { | |
| fprintf(stderr, "Failed to allocate the %s codec context\n", | |
| av_get_media_type_string(type)); | |
| return AVERROR(ENOMEM); | |
| } | |
| /* Copy codec parameters from input stream to output codec context */ | |
| if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) { | |
| fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n", | |
| av_get_media_type_string(type)); | |
| return ret; | |
| } | |
| // 明确输出类型 | |
| (*dec_ctx)->request_sample_fmt = (*dec_ctx)->sample_fmt == AV_SAMPLE_FMT_S16P ? AV_SAMPLE_FMT_S16 : (*dec_ctx)->sample_fmt; | |
| (*dec_ctx)->request_sample_fmt = (*dec_ctx)->sample_fmt == AV_SAMPLE_FMT_S32P ? AV_SAMPLE_FMT_S32 : (*dec_ctx)->sample_fmt; | |
| /* Init the decoders */ | |
| if ((ret = avcodec_open2(*dec_ctx, dec, NULL)) < 0) { | |
| fprintf(stderr, "Failed to open %s codec\n", | |
| av_get_media_type_string(type)); | |
| return ret; | |
| } | |
| *stream_idx = stream_index; | |
| } | |
| return 0; | |
| } | |
| static int get_format_from_sample_fmt(const char **fmt, | |
| enum AVSampleFormat sample_fmt) | |
| { | |
| int i; | |
| struct sample_fmt_entry { | |
| enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le; | |
| } sample_fmt_entries[] = { | |
| { AV_SAMPLE_FMT_U8, "u8", "u8" }, | |
| { AV_SAMPLE_FMT_S16, "s16be", "s16le" }, | |
| { AV_SAMPLE_FMT_S32, "s32be", "s32le" }, | |
| { AV_SAMPLE_FMT_FLT, "f32be", "f32le" }, | |
| { AV_SAMPLE_FMT_DBL, "f64be", "f64le" }, | |
| }; | |
| *fmt = NULL; | |
| for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) { | |
| struct sample_fmt_entry *entry = &sample_fmt_entries[i]; | |
| if (sample_fmt == entry->sample_fmt) { | |
| *fmt = AV_NE(entry->fmt_be, entry->fmt_le); | |
| return 0; | |
| } | |
| } | |
| fprintf(stderr, | |
| "sample format %s is not supported as output format\n", | |
| av_get_sample_fmt_name(sample_fmt)); | |
| return -1; | |
| } | |
| int main (int argc, char **argv) | |
| { | |
| int ret = 0; | |
| // if (argc != 4) { | |
| // fprintf(stderr, "usage: %s input_file video_output_file audio_output_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" | |
| // "video frames to a rawvideo file named video_output_file, and decoded\n" | |
| // "audio frames to a rawaudio file named audio_output_file.\n", | |
| // argv[0]); | |
| // exit(1); | |
| // } | |
| src_filename = argv[1]; | |
| audio_dst_filename = argv[2]; | |
| /* open input file, and allocate format context */ | |
| if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { | |
| fprintf(stderr, "Could not open source file %s\n", src_filename); | |
| exit(1); | |
| } | |
| /* retrieve stream information */ | |
| if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { | |
| fprintf(stderr, "Could not find stream information\n"); | |
| exit(1); | |
| } | |
| if (open_codec_context(&audio_stream_idx, &audio_dec_ctx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) { | |
| audio_stream = fmt_ctx->streams[audio_stream_idx]; | |
| // audio_dst_file = fopen(audio_dst_filename, "wb"); | |
| // if (!audio_dst_file) { | |
| // fprintf(stderr, "Could not open destination file %s\n", audio_dst_filename); | |
| // ret = 1; | |
| // goto end; | |
| // } | |
| } | |
| printf("nb_streams %d\n", fmt_ctx->nb_streams); | |
| /* dump input information to stderr */ | |
| // av_dump_format(fmt_ctx, 0, src_filename, 0); | |
| if (!audio_stream) { | |
| fprintf(stderr, "Could not find audio stream in the input, aborting\n"); | |
| ret = 1; | |
| goto end; | |
| } | |
| frame = av_frame_alloc(); | |
| if (!frame) { | |
| fprintf(stderr, "Could not allocate frame\n"); | |
| ret = AVERROR(ENOMEM); | |
| goto end; | |
| } | |
| pkt = av_packet_alloc(); | |
| if (!pkt) { | |
| fprintf(stderr, "Could not allocate packet\n"); | |
| ret = AVERROR(ENOMEM); | |
| goto end; | |
| } | |
| if (audio_stream) | |
| printf("Demuxing audio from file '%s' into '%s'\n", src_filename, audio_dst_filename); | |
| /* read frames from the file */ | |
| while (av_read_frame(fmt_ctx, pkt) >= 0) | |
| { | |
| // check if the packet belongs to a stream we are interested in, otherwise | |
| // skip it | |
| if (pkt->stream_index == audio_stream_idx) | |
| ret = decode_packet(audio_dec_ctx, pkt); | |
| av_packet_unref(pkt); | |
| if (ret < 0) | |
| break; | |
| } | |
| /* flush the decoders */ | |
| if (audio_dec_ctx) | |
| decode_packet(audio_dec_ctx, NULL); | |
| printf("Demuxing succeeded.\n"); | |
| if (audio_stream) { | |
| enum AVSampleFormat sfmt = audio_dec_ctx->sample_fmt; | |
| int n_channels = audio_dec_ctx->ch_layout.nb_channels; | |
| const char *fmt; | |
| if (av_sample_fmt_is_planar(sfmt)) { | |
| const char *packed = av_get_sample_fmt_name(sfmt); | |
| printf("Warning: the sample format the decoder produced is planar " | |
| "(%s). This example will output the first channel only.\n", | |
| packed ? packed : "?"); | |
| sfmt = av_get_packed_sample_fmt(sfmt); | |
| n_channels = 1; | |
| } | |
| if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0) | |
| goto end; | |
| printf("Play the output audio file with the command:\n" | |
| "ffplay -f %s -ac %d -ar %d %s\n", | |
| fmt, n_channels, audio_dec_ctx->sample_rate, | |
| audio_dst_filename); | |
| } | |
| end: | |
| avcodec_free_context(&audio_dec_ctx); | |
| avformat_close_input(&fmt_ctx); | |
| if (audio_dst_file) | |
| fclose(audio_dst_file); | |
| av_packet_free(&pkt); | |
| av_frame_free(&frame); | |
| return ret < 0; | |
| } | |
| // 补全依赖 | |
| static char pbuffer[4096]; | |
| void av_log(void *avcl, int level, const char *fmt, ...) | |
| { | |
| va_list args; | |
| va_start(args, fmt); | |
| vsnprintf(pbuffer, 4096, fmt, args); | |
| va_end(args); | |
| puts(pbuffer); | |
| } | |
| int av_log_get_level(void) | |
| { | |
| return 0; | |
| } | |
| int64_t av_gettime_relative(void) | |
| { | |
| return 0; | |
| } | |
| int av_usleep(unsigned usec) | |
| { | |
| return 0; | |
| } | |
| int64_t av_gettime(void) | |
| { | |
| return 0; | |
| } | |
| const char *av_default_item_name(void *ptr) | |
| { | |
| return (*(AVClass **)ptr)->class_name; | |
| } | |
| uint32_t av_get_random_seed() | |
| { | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment