基于ffmpeg的简单音视频编解码的例子

简介: 近日需要做一个视频转码服务器,对我这样一个在该领域的新手来说却是够我折腾一番,在别人的建议下开始研究开源ffmpeg项目,下面是在代码中看到的一 段例子代码,对我的学习非常有帮助。该例子代码包含音频的解码/编码和视频的编码/解码,其中主要用到编解码的libavcodec组件。

近日需要做一个视频转码服务器,对我这样一个在该领域的新手来说却是够我折腾一番,在别人的建议下开始研究开源ffmpeg项目,下面是在代码中看到的一 段例子代码,对我的学习非常有帮助。该例子代码包含音频的解码/编码和视频的编码/解码,其中主要用到编解码的libavcodec组件。以下是完整的例 子,代码自身的注释足够清晰了。
/** 
 * @file 
 * libavcodec API use example. 
 * 
 * Note that libavcodec only handles codecs (mpeg, mpeg4, etc...), 
 * not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...).  
 * See library 'libavformat' for the format handling 
 * @example doc/examples/decoding_encoding.c 
 */ 
 
#include <math.h> 
 
#include <libavutil/opt.h> 
#include <libavcodec/avcodec.h> 
#include <libavutil/channel_layout.h> 
#include <libavutil/common.h> 
#include <libavutil/imgutils.h> 
#include <libavutil/mathematics.h> 
#include <libavutil/samplefmt.h> 
 
#define INBUF_SIZE 4096 
#define AUDIO_INBUF_SIZE 20480 
#define AUDIO_REFILL_THRESH 4096 
 
/* check that a given sample format is supported by the encoder */ 
static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) 

    const enum AVSampleFormat *p = codec->sample_fmts; 
 
    while (*p != AV_SAMPLE_FMT_NONE) { 
        if (*p == sample_fmt) 
            return 1; 
        p++; 
    } 
    return 0; 

 
/* just pick the highest supported samplerate */ 
static int select_sample_rate(AVCodec *codec) 

    const int *p; 
    int best_samplerate = 0; 
 
    if (!codec->supported_samplerates) 
        return 44100; 
 
    p = codec->supported_samplerates; 
    while (*p) { 
        best_samplerate = FFMAX(*p, best_samplerate); 
        p++; 
    } 
    return best_samplerate; 

 
/* select layout with the highest channel count */ 
static int select_channel_layout(AVCodec *codec) 

    const uint64_t *p; 
    uint64_t best_ch_layout = 0; 
    int best_nb_channells   = 0; 
 
    if (!codec->channel_layouts) 
        return AV_CH_LAYOUT_STEREO; 
 
    p = codec->channel_layouts; 
    while (*p) { 
        int nb_channels = av_get_channel_layout_nb_channels(*p); 
 
        if (nb_channels > best_nb_channells) { 
            best_ch_layout    = *p; 
            best_nb_channells = nb_channels; 
        } 
        p++; 
    } 
    return best_ch_layout; 

 
/* 
 * Audio encoding example 
 */ 
static void audio_encode_example(const char *filename) 

    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    AVFrame *frame; 
    AVPacket pkt; 
    int i, j, k, ret, got_output; 
    int buffer_size; 
    FILE *f; 
    uint16_t *samples; 
    float t, tincr; 
 
    printf("Encode audio file %s\n", filename); 
 
    /* find the MP2 encoder */ 
    codec = avcodec_find_encoder(AV_CODEC_ID_MP2); 
    if (!codec) { 
        fprintf(stderr, "Codec not found\n"); 
        exit(1); 
    } 
 
    c = avcodec_alloc_context3(codec); 
    if (!c) { 
        fprintf(stderr, "Could not allocate audio codec context\n"); 
        exit(1); 
    } 
 
    /* put sample parameters */ 
    c->bit_rate = 64000; 
 
    /* check that the encoder supports s16 pcm input */ 
    c->sample_fmt = AV_SAMPLE_FMT_S16; 
    if (!check_sample_fmt(codec, c->sample_fmt)) { 
        fprintf(stderr, "Encoder does not support sample format %s", 
                av_get_sample_fmt_name(c->sample_fmt)); 
        exit(1); 
    } 
 
    /* select other audio parameters supported by the encoder */ 
    c->sample_rate    = select_sample_rate(codec); 
    c->channel_layout = select_channel_layout(codec); 
    c->channels       = av_get_channel_layout_nb_channels(c->channel_layout); 
 
    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
        fprintf(stderr, "Could not open codec\n"); 
        exit(1); 
    } 
 
    f = fopen(filename, "wb"); 
    if (!f) { 
        fprintf(stderr, "Could not open %s\n", filename); 
        exit(1); 
    } 
 
    /* frame containing input raw audio */ 
    frame = avcodec_alloc_frame(); 
    if (!frame) { 
        fprintf(stderr, "Could not allocate audio frame\n"); 
        exit(1); 
    } 
 
    frame->nb_samples     = c->frame_size; 
    frame->format         = c->sample_fmt; 
    frame->channel_layout = c->channel_layout; 
 
    /* the codec gives us the frame size, in samples, 
     * we calculate the size of the samples buffer in bytes */ 
    buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size, 
                                             c->sample_fmt, 0); 
    samples = av_malloc(buffer_size); 
    if (!samples) { 
        fprintf(stderr, "Could not allocate %d bytes for samples buffer\n", 
                buffer_size); 
        exit(1); 
    } 
    /* setup the data pointers in the AVFrame */ 
    ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, 
                                   (const uint8_t*)samples, buffer_size, 0); 
    if (ret < 0) { 
        fprintf(stderr, "Could not setup audio frame\n"); 
        exit(1); 
    } 
 
    /* encode a single tone sound */ 
    t = 0; 
    tincr = 2 * M_PI * 440.0 / c->sample_rate; 
    for(i=0;i<200;i++) { 
        av_init_packet(&pkt); 
        pkt.data = NULL; // packet data will be allocated by the encoder 
        pkt.size = 0; 
 
        for (j = 0; j < c->frame_size; j++) { 
            samples[2*j] = (int)(sin(t) * 10000); 
 
            for (k = 1; k < c->channels; k++) 
                samples[2*j + k] = samples[2*j]; 
            t += tincr; 
        } 
        /* encode the samples */ 
        ret = avcodec_encode_audio2(c, &pkt, frame, &got_output); 
        if (ret < 0) { 
            fprintf(stderr, "Error encoding audio frame\n"); 
            exit(1); 
        } 
        if (got_output) { 
            fwrite(pkt.data, 1, pkt.size, f); 
            av_free_packet(&pkt); 
        } 
    } 
 
    /* get the delayed frames */ 
    for (got_output = 1; got_output; i++) { 
        ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output); 
        if (ret < 0) { 
            fprintf(stderr, "Error encoding frame\n"); 
            exit(1); 
        } 
 
        if (got_output) { 
            fwrite(pkt.data, 1, pkt.size, f); 
            av_free_packet(&pkt); 
        } 
    } 
    fclose(f); 
 
    av_freep(&samples); 
    avcodec_free_frame(&frame); 
    avcodec_close(c); 
    av_free(c); 

 
/* 
 * Audio decoding. 
 */ 
static void audio_decode_example(const char *outfilename, const char *filename) 

    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    int len; 
    FILE *f, *outfile; 
    uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; 
    AVPacket avpkt; 
    AVFrame *decoded_frame = NULL; 
 
    av_init_packet(&avpkt); 
 
    printf("Decode audio file %s to %s\n", filename, outfilename); 
 
    /* find the mpeg audio decoder */ 
    codec = avcodec_find_decoder(AV_CODEC_ID_MP2); 
    if (!codec) { 
        fprintf(stderr, "Codec not found\n"); 
        exit(1); 
    } 
 
    c = avcodec_alloc_context3(codec); 
    if (!c) { 
        fprintf(stderr, "Could not allocate audio codec context\n"); 
        exit(1); 
    } 
 
    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
        fprintf(stderr, "Could not open codec\n"); 
        exit(1); 
    } 
 
    f = fopen(filename, "rb"); 
    if (!f) { 
        fprintf(stderr, "Could not open %s\n", filename); 
        exit(1); 
    } 
    outfile = fopen(outfilename, "wb"); 
    if (!outfile) { 
        av_free(c); 
        exit(1); 
    } 
 
    /* decode until eof */ 
    avpkt.data = inbuf; 
    avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); 
 
    while (avpkt.size > 0) { 
        int got_frame = 0; 
 
        if (!decoded_frame) { 
            if (!(decoded_frame = avcodec_alloc_frame())) { 
                fprintf(stderr, "Could not allocate audio frame\n"); 
                exit(1); 
            } 
        } else 
            avcodec_get_frame_defaults(decoded_frame); 
 
        len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt); 
        if (len < 0) { 
            fprintf(stderr, "Error while decoding\n"); 
            exit(1); 
        } 
        if (got_frame) { 
            /* if a frame has been decoded, output it */ 
            int data_size = av_samples_get_buffer_size(NULL, c->channels, 
                                                       decoded_frame->nb_samples, 
                                                       c->sample_fmt, 1); 
            fwrite(decoded_frame->data[0], 1, data_size, outfile); 
        } 
        avpkt.size -= len; 
        avpkt.data += len; 
        avpkt.dts = 
        avpkt.pts = AV_NOPTS_VALUE; 
        if (avpkt.size < AUDIO_REFILL_THRESH) { 
            /* Refill the input buffer, to avoid trying to decode 
             * incomplete frames. Instead of this, one could also use 
             * a parser, or use a proper container format through 
             * libavformat. */ 
            memmove(inbuf, avpkt.data, avpkt.size); 
            avpkt.data = inbuf; 
            len = fread(avpkt.data + avpkt.size, 1, 
                        AUDIO_INBUF_SIZE - avpkt.size, f); 
            if (len > 0) 
                avpkt.size += len; 
        } 
    } 
 
    fclose(outfile); 
    fclose(f); 
 
    avcodec_close(c); 
    av_free(c); 
    avcodec_free_frame(&decoded_frame); 

 
/* 
 * Video encoding example 
 */ 
static void video_encode_example(const char *filename, int codec_id) 

    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    int i, ret, x, y, got_output; 
    FILE *f; 
    AVFrame *frame; 
    AVPacket pkt; 
    uint8_t endcode[] = { 0, 0, 1, 0xb7 }; 
 
    printf("Encode video file %s\n", filename); 
 
    /* find the mpeg1 video encoder */ 
    codec = avcodec_find_encoder(codec_id); 
    if (!codec) { 
        fprintf(stderr, "Codec not found\n"); 
        exit(1); 
    } 
 
    c = avcodec_alloc_context3(codec); 
    if (!c) { 
        fprintf(stderr, "Could not allocate video codec context\n"); 
        exit(1); 
    } 
 
    /* put sample parameters */ 
    c->bit_rate = 400000; 
    /* resolution must be a multiple of two */ 
    c->width = 352; 
    c->height = 288; 
    /* frames per second */ 
    c->time_base= (AVRational){1,25}; 
    c->gop_size = 10; /* emit one intra frame every ten frames */ 
    c->max_b_frames=1; 
    c->pix_fmt = AV_PIX_FMT_YUV420P; 
 
    if(codec_id == AV_CODEC_ID_H264) 
        av_opt_set(c->priv_data, "preset", "slow", 0); 
 
    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
        fprintf(stderr, "Could not open codec\n"); 
        exit(1); 
    } 
 
    f = fopen(filename, "wb"); 
    if (!f) { 
        fprintf(stderr, "Could not open %s\n", filename); 
        exit(1); 
    } 
 
    frame = avcodec_alloc_frame(); 
    if (!frame) { 
        fprintf(stderr, "Could not allocate video frame\n"); 
        exit(1); 
    } 
    frame->format = c->pix_fmt; 
    frame->width  = c->width; 
    frame->height = c->height; 
 
    /* the image can be allocated by any means and av_image_alloc() is 
     * just the most convenient way if av_malloc() is to be used */ 
    ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, 
                         c->pix_fmt, 32); 
    if (ret < 0) { 
        fprintf(stderr, "Could not allocate raw picture buffer\n"); 
        exit(1); 
    } 
 
    /* encode 1 second of video */ 
    for(i=0;i<25;i++) { 
        av_init_packet(&pkt); 
        pkt.data = NULL;    // packet data will be allocated by the encoder 
        pkt.size = 0; 
 
        fflush(stdout); 
        /* prepare a dummy image */ 
        /* Y */ 
        for(y=0;y<c->height;y++) { 
            for(x=0;x<c->width;x++) { 
                frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3; 
            } 
        } 
 
        /* Cb and Cr */ 
        for(y=0;y<c->height/2;y++) { 
            for(x=0;x<c->width/2;x++) { 
                frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2; 
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5; 
            } 
        } 
 
        frame->pts = i; 
 
        /* encode the image */ 
        ret = avcodec_encode_video2(c, &pkt, frame, &got_output); 
        if (ret < 0) { 
            fprintf(stderr, "Error encoding frame\n"); 
            exit(1); 
        } 
 
        if (got_output) { 
            printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
            fwrite(pkt.data, 1, pkt.size, f); 
            av_free_packet(&pkt); 
        } 
    } 
 
    /* get the delayed frames */ 
    for (got_output = 1; got_output; i++) { 
        fflush(stdout); 
 
        ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); 
        if (ret < 0) { 
            fprintf(stderr, "Error encoding frame\n"); 
            exit(1); 
        } 
 
        if (got_output) { 
            printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
            fwrite(pkt.data, 1, pkt.size, f); 
            av_free_packet(&pkt); 
        } 
    } 
 
    /* add sequence end code to have a real mpeg file */ 
    fwrite(endcode, 1, sizeof(endcode), f); 
    fclose(f); 
 
    avcodec_close(c); 
    av_free(c); 
    av_freep(&frame->data[0]); 
    avcodec_free_frame(&frame); 
    printf("\n"); 

 
/* 
 * Video decoding example 
 */ 
 
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, 
                     char *filename) 

    FILE *f; 
    int i; 
 
    f=fopen(filename,"w"); 
    fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255); 
    for(i=0;i<ysize;i++) 
        fwrite(buf + i * wrap,1,xsize,f); 
    fclose(f); 

 
static int decode_write_frame(const char *outfilename, AVCodecContext *avctx, 
                              AVFrame *frame, int *frame_count, AVPacket *pkt, int last) 

    int len, got_frame; 
    char buf[1024]; 
 
    len = avcodec_decode_video2(avctx, frame, &got_frame, pkt); 
    if (len < 0) { 
        fprintf(stderr, "Error while decoding frame %d\n", *frame_count); 
        return len; 
    } 
    if (got_frame) { 
        printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count); 
        fflush(stdout); 
 
        /* the picture is allocated by the decoder, no need to free it */ 
        snprintf(buf, sizeof(buf), outfilename, *frame_count); 
        pgm_save(frame->data[0], frame->linesize[0], 
                 avctx->width, avctx->height, buf); 
        (*frame_count)++; 
    } 
    if (pkt->data) { 
        pkt->size -= len; 
        pkt->data += len; 
    } 
    return 0; 

 
static void video_decode_example(const char *outfilename, const char *filename) 

    AVCodec *codec; 
    AVCodecContext *c= NULL; 
    int frame_count; 
    FILE *f; 
    AVFrame *frame; 
    uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; 
    AVPacket avpkt; 
 
    av_init_packet(&avpkt); 
 
    /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */ 
    memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE); 
 
    printf("Decode video file %s to %s\n", filename, outfilename); 
 
    /* find the mpeg1 video decoder */ 
    codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO); 
    if (!codec) { 
        fprintf(stderr, "Codec not found\n"); 
        exit(1); 
    } 
 
    c = avcodec_alloc_context3(codec); 
    if (!c) { 
        fprintf(stderr, "Could not allocate video codec context\n"); 
        exit(1); 
    } 
 
    if(codec->capabilities&CODEC_CAP_TRUNCATED) 
        c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */ 
 
    /* For some codecs, such as msmpeg4 and mpeg4, width and height 
       MUST be initialized there because this information is not 
       available in the bitstream. */ 
 
    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
        fprintf(stderr, "Could not open codec\n"); 
        exit(1); 
    } 
 
    f = fopen(filename, "rb"); 
    if (!f) { 
        fprintf(stderr, "Could not open %s\n", filename); 
        exit(1); 
    } 
 
    frame = avcodec_alloc_frame(); 
    if (!frame) { 
        fprintf(stderr, "Could not allocate video frame\n"); 
        exit(1); 
    } 
 
    frame_count = 0; 
    for(;;) { 
        avpkt.size = fread(inbuf, 1, INBUF_SIZE, f); 
        if (avpkt.size == 0) 
            break; 
 
        /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio) 
           and this is the only method to use them because you cannot 
           know the compressed data size before analysing it. 
 
           BUT some other codecs (msmpeg4, mpeg4) are inherently frame 
           based, so you must call them with all the data for one 
           frame exactly. You must also initialize 'width' and 
           'height' before initializing them. */ 
 
        /* NOTE2: some codecs allow the raw parameters (frame size, 
           sample rate) to be changed at any frame. We handle this, so 
           you should also take care of it */ 
 
        /* here, we use a stream based decoder (mpeg1video), so we 
           feed decoder and see if it could decode a frame */ 
        avpkt.data = inbuf; 
        while (avpkt.size > 0) 
            if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0) 
                exit(1); 
    } 
 
    /* some codecs, such as MPEG, transmit the I and P frame with a 
       latency of one frame. You must do the following to have a 
       chance to get the last frame of the video */ 
    avpkt.data = NULL; 
    avpkt.size = 0; 
    decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1); 
 
    fclose(f); 
 
    avcodec_close(c); 
    av_free(c); 
    avcodec_free_frame(&frame); 
    printf("\n"); 

 
int main(int argc, char **argv) 

    const char *output_type; 
 
    /* register all the codecs */ 
    avcodec_register_all(); 
 
    if (argc < 2) { 
        printf("usage: %s output_type\n" 
               "API example program to decode/encode a media stream with libavcodec.\n" 
               "This program generates a synthetic stream and encodes it to a file\n" 
               "named test.h264, test.mp2 or test.mpg depending on output_type.\n" 
               "The encoded stream is then decoded and written to a raw data output.\n" 
               "output_type must be choosen between 'h264', 'mp2', 'mpg'.\n", 
               argv[0]); 
        return 1; 
    } 
    output_type = argv[1]; 
 
    if (!strcmp(output_type, "h264")) { 
        video_encode_example("test.h264", AV_CODEC_ID_H264); 
    } else if (!strcmp(output_type, "mp2")) { 
        audio_encode_example("test.mp2"); 
        audio_decode_example("test.sw", "test.mp2"); 
    } else if (!strcmp(output_type, "mpg")) { 
        video_encode_example("test.mpg", AV_CODEC_ID_MPEG1VIDEO); 
        video_decode_example("test%02d.pgm", "test.mpg"); 
    } else { 
        fprintf(stderr, "Invalid output type '%s', choose between 'h264', 'mp2', or 'mpg'\n", 
                output_type); 
        return 1; 
    } 
 
    return 0; 

 

目录
相关文章
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
1196 4
|
编解码
项目实战——Qt实现FFmpeg音视频转码器(二)
项目实战——Qt实现FFmpeg音视频转码器(二)
237 0
|
编解码 编译器
项目实战——Qt实现FFmpeg音视频转码器(一)
项目实战——Qt实现FFmpeg音视频转码器(一)
391 0
|
Web App开发 5G Linux
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
一年一度的毕业季来临,计算机专业的毕业设计尤为重要,不仅关乎学业评价还积累实战经验。选择紧跟5G技术趋势的音视频APP作为课题极具吸引力。这里推荐三类应用:一是融合WebRTC技术实现视频通话的即时通信APP;二是具备在线直播功能的短视频分享平台,涉及RTMP/SRT等直播技术;三是具有自定义动画特效及卡拉OK歌词字幕功能的视频剪辑工具。这些项目不仅技术含量高,也符合市场需求,是毕业设计的理想选择。
212 6
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
|
Android开发 计算机视觉 C++
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
音视频编程对许多程序员来说是一片充满挑战的领域,但借助如OpenCV、LearnOpenGL、FFmpeg、OBS Studio及VLC media player等强大的开源工具,可以降低入门门槛。这些框架不仅覆盖了计算机视觉、图形渲染,还包括多媒体处理与直播技术,通过多种编程语言如Python、C++的应用,使得音视频开发更为便捷。例如,OpenCV支持跨平台的视觉应用开发,FFmpeg则擅长多媒体文件的处理与转换,而VLC media player则是验证音视频文件质量的有效工具。
327 0
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
778 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
达摩院 语音技术 异构计算
语音识别-免费开源的语音转文本软件Whisper的本地搭建详细教程,python版本是3.805,ffmpeg是专门处理音视频的,ffmpeg的下载链接,现在要求安装python和ffmpeg
语音识别-免费开源的语音转文本软件Whisper的本地搭建详细教程,python版本是3.805,ffmpeg是专门处理音视频的,ffmpeg的下载链接,现在要求安装python和ffmpeg
|
存储 编解码 容器
FFmpeg avformat_open_input() 函数返回错误protocol not found解决方法(实测有效!附简单FFMPEG的编解码流程)
我个人出现这个错误的时候是在打开文件时报的错误,开始以为我需要加上资源文件,那样QT确实能检测到文件的存在,但是在Debug中他是检测不到这个文件的。
1175 1
|
存储 编解码 Linux
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
174 1