视频编码案例

视频编码案例


目录

  1. FFmpeg视频编码流程
  2. H.264码率设置
  3. FFmpeg与H264编码指南
  4. X264参数之zerolatency的分析
  5. YUV编码成H.264案例

1. FFmpeg视频编码流程

在这里插入图片描述

  1. 从本地读取YUV数据编码为h264格式的数据,然后再存⼊到本地,编码后的数据有带startcode。
1. 函数说明
  1. avcodec_find_encoder_by_name:根据指定的编码器名称查找注册的编码器。
  2. avcodec_alloc_context3:为AVCodecContext分配内存。
  3. avcodec_open2:打开编解码器。
  4. avcodec_send_frame:将AVFrame⾮压缩数据给编码器。。
  5. avcodec_receive_packet:获取到编码后的AVPacket数据。
  6. av_frame_get_buffer: 为⾳频或视频数据分配新的buffer。在调⽤这个函数之前,必须在AVFame上设置好以下属性:format(视频为像素格式,⾳频为样本格式)、nb_samples(样本个数,针对⾳频)、channel_layout(通道类型,针对⾳频)、width/height(宽⾼,针对视频)。
  7. av_frame_make_writable:确保AVFrame是可写的,尽可能避免数据的复制。如果AVFrame不是是可写的,将分配新的buffer和复制数据。
  8. av_image_fill_arrays: 存储⼀帧像素数据存储到AVFrame对应的data buffer。
  9. 编码出来的h264数据可以直接使⽤ffplay播放,也可以使⽤VLC播放。
2. av_image_get_buffer_size
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
  1. 函数的作⽤是通过指定像素格式、图像宽、图像⾼来计算所需的内存⼤⼩
  2. 重点说明⼀个参数align:此参数是设定内存对⻬的对⻬数,也就是按多⼤的字节进⾏内存对⻬:
    1. ⽐如设置为1,表示按1字节对⻬,那么得到的结果就是与实际的内存⼤⼩⼀样。
    2. 再⽐如设置为4,表示按4字节对⻬。也就是内存的起始地址必须是4的整倍数。
3. av_image_alloc
  1. av_image_alloc()是这样定义的。此函数的功能是按照指定的宽、⾼、像素格式来分配图像内存。
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
  1. pointers[4]:保存图像通道的地址。如果是RGB,则前三个指针分别指向R,G,B的内存地址。第四个指针保留不⽤ linesizes[4]:保存图像每个通道的内存对⻬的步⻓,即⼀⾏的对⻬内存的宽度,此值⼤⼩等于图像宽度。
  2. w: 要申请内存的图像宽度。
  3. h: 要申请内存的图像⾼度。
  4. pix_fmt: 要申请内存的图像的像素格式。
  5. align: ⽤于内存对⻬的值。
  6. 返回值:所申请的内存空间的总⼤⼩。如果是负值,表示申请失败。
4. av_image_fill_arrays
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align);
  1. av_image_fill_arrays()函数⾃身不具备内存申请的功能,此函数类似于格式化已经申请的内存,即通过av_malloc()函数申请的内存空间,或者av_frame_get_buffer()函数申请的内存空间。再者,av_image_fill_arrays()中参数具体说明:
  2. dst_data[4]: [out]对申请的内存格式化为三个通道后,分别保存其地址
  3. dst_linesize[4]: [out]格式化的内存的步⻓(即内存对⻬后的宽度)
  4. *src: [in]av_alloc()函数申请的内存地址。
  5. pix_fmt: [in] 申请 src内存时的像素格式
  6. width: [in]申请src内存时指定的宽度
  7. height: [in]申请scr内存时指定的⾼度
  8. align: [in]申请src内存时指定的对⻬字节数

2. H.264码率设置

1. 什么是视频码率
  1. 视频码率是视频数据(包含视频⾊彩量、亮度量、像素量)每秒输出的位数。⼀般⽤的单位是kbps。
2. 设置视频码率的必要性
  1. 在⽹络视频应⽤中,视频质量和⽹络带宽占⽤是相⽭盾的。通常情况下,视频流占⽤的带宽越⾼则视频质量也越⾼,需要的⽹络带宽也越⼤,解决这⼀⽭盾的钥匙当然是视频编解码技术。评判⼀种视频编解码技术的优劣,是⽐较在相同的带宽条件下,哪个视频质量更好;在相同的视频质量条件下,哪个占⽤的⽹络带宽更少(⽂件体积⼩)。
  2. 是不是视频码率越⾼,质量越好呢?理论上是这样的。然⽽在我们⾁眼分辨的范围内,当码率⾼到⼀定程度时,就没有什么差别了。所以码率设置有它的最优值,H.264(也叫AVC或X264)的⽂件中,视频的建议码率如下
视频⼤⼩分辨率推荐码率
480P720X4801800Kbps
720P1280X7203500Kbps
1080P1920X10808500Kbps
3. ⼿机设置码率建议
项⽬计算公式192X144320X240480X360640X4801280X7201920X1080
极低码率(宽X⾼X3)/430kbps60kbps120kbps250kbps500kbps1000kbps
低码率(宽X⾼X3)/260kbps120kbps250kbps500kbps1000kbps2000kbps
中码率(宽X⾼X3)120kbps250kbps500kbps1000kbps2000kbps4000kbps
⾼码率(宽X⾼X3)X2250kbps500kbps1000kbps2000kbps4000kbps8000kbps
极⾼码率(宽X⾼X3)X4500kbps1000kbps2000kbps4000kbps8000kbps16000kbps

3. FFmpeg与H264编码指南

  1. 鉴于x264的参数众多,各种参数的配合复杂,为了使⽤者⽅便,x264建议如⽆特别需要可使⽤preset和tune设置。这套开发者推荐的参数较为合理,可在此基础上在调整⼀些具体参数以符合⾃⼰需要,⼿动设定的参数会覆盖preset和tune⾥的参数。

  2. 使⽤ ffmpeg -h encoder=libx264 命令查询相关⽀持的参数

  3. 英⽂地址:https://trac.ffmpeg.org/wiki/Encode/H.264。内容有⼀定出⼊,但是可以借鉴学习。

  4. x264是⼀个 H.264/MPEG4 AVC 编码器,对于普通⽤户通常有两种码率控制模式:CRF(Constant Rate Factor)和Two pass ABR。码率控制是⼀种决定为每⼀个视频帧分配多少⽐特数的⽅法,它将决定⽂件的⼤⼩和质量的分配。

  5. 如果你在编译和安装libx264 ⽅⾯需要帮助,请查看ffmpeg和x264编译指南:

  6. http://ffmpeg.org/trac/ffmpeg/wiki/CompilationGuide

  7. 参考:h264编码参数

1. CRF(Constant Rate Factor):
1. 选择⼀个CRF值
  1. 量化⽐例的范围为0到51,其中0为⽆损模式,23为缺省值,51可能是最差的。该数字越⼩,图像质量越好。从主观上讲,18~28是⼀个合理的范围。18往往被认为从视觉上看是⽆损的,它的输出视频质量和输⼊视频⼀模⼀样或者说相差⽆⼏。但从技术的⻆度来讲,它依然是有损压缩。
  2. 若CRF值加6,输出码率⼤概减少⼀半;若CRF值减6,输出码率翻倍。通常是在保证可接受视频质量的前提下选择⼀个最⼤的CRF值,如果输出视频质量很好,那就尝试⼀个更⼤的值,如果看起来很糟,那就尝试⼀个⼩⼀点值。
  3. 注释:本⽂所提到的量化⽐例只适⽤于8-bit x264(10-bit x264的量化⽐例 为0~63),你可以使⽤x264 --help命令在Output bit depth选项查看输出位深,在各种版本中,8bit是最常⻅的
2. 选择⼀个preset和tune
1. preset
  1. 预设是⼀系列参数的集合,这个集合能够在编码速度和压缩率之间做出⼀个权衡。⼀个编码速度稍慢的预设会提供更⾼的压缩效率(压缩效率是以⽂件⼤⼩来衡量的)。这就是说,假如你想得到⼀个指定⼤⼩的⽂件或者采⽤恒定⽐特率编码模式,你可以采⽤⼀个较慢的预设来获得更好的质量。同样的,对于恒定质量编码模式,你可以通过选择⼀个较慢的预设轻松地节省⽐特率。
  2. 如果你很有耐⼼,通常的建议是使⽤最慢的预设。⽬前所有的预设按照编码速度降序排列为:
    1. ultrafast
    2. superfast
    3. veryfast
    4. faster
    5. fast
    6. medium – default preset
    7. slow
    8. slower
    9. veryslow
    10. placebo - ignore this as it is not useful (see FAQ)
  3. 默认为medium级别
  4. 你可以使⽤–preset来查看预设列表,也可以通过x264 --fullhelp来查看预设所采⽤的参数配置。
  5. 针对 libx264做过简单的各选项对⽐测试,结果如下图
    在这里插入图片描述
  6. 从图中可以看出,当其他参数固定时,选择不同的preset,对应的码率和编码时间都不⼀样
2. tune
  1. tune是x264中重要性仅次于preset的选项,它是视觉优化的参数,tune可以理解为视频偏好(或者视频类型),tune不是⼀个单⼀的参数,⽽是由⼀组参数构成-tune来改变参数设置。当前的 tune包括:

    1. film:电影类型,对视频的质量⾮常严格时使⽤该选项
    2. animation:动画⽚,压缩的视频是动画⽚时使⽤该选项
    3. grain:颗粒物很重,该选项适⽤于颗粒感很重的视频
    4. stillimage:静态图像,该选项主要⽤于静⽌画⾯⽐较多的视频
    5. psnr:提⾼psnr,该选项编码出来的视频psnr⽐较⾼
    6. ssim:提⾼ssim,该选项编码出来的视频ssim⽐较⾼
    7. fastdecode:快速解码,该选项有利于快速解码
    8. zerolatency:零延迟,该选项主要⽤于视频直播
  2. 如果你不确定使⽤哪个选项或者说你的输⼊与所有的tune皆不匹配,你可以忽略–tune 选项。

  3. 你可以使⽤-tune来查看tune列表,也可以通过x264 --fullhelp来查看tune所采⽤的参数配置

3. profile
  1. 另外⼀个可选的参数是-profile:v,它可以将你的输出限制到⼀个特定的 H.264 profile。⼀些⾮常⽼的或者要被淘汰的设备仅⽀持有限的选项,⽐如只⽀持baseline或者main。

  2. 所有的profile 包括:

    1. baseline profile:基本画质。⽀持I/P 帧,只⽀持⽆交错(Progressive)和CAVLC;
    2. extended profile:进阶画质。⽀持I/P/B/SP/SI 帧,只⽀持⽆交错(Progressive)和CAVLC;
    3. main profile:主流画质。提供I/P/B 帧,⽀持⽆交错(Progressive)和交错(Interlaced),也⽀持CAVLC 和CABAC 的⽀持;
    4. high profile:⾼级画质。在main Profile 的基础上增加了8x8内部预测、⾃定义量化、 ⽆损视频编码和更多的YUV 格式;
  3. 想要说明H.264 high profile与H.264 main profile的区别就要讲到H.264的技术发展了。JVT于2003年完成H.264基本部分标准制定⼯作,包含baseline profile、extended profile和main profile,分别包括不同的编码⼯具。之后JVT⼜完成了H.264 FRExt(即:Fidelity Range Extensions)扩展部分(Amendment)的制定⼯作,包括high profile(HP)、high 10 profile(Hi10P)、high 4:2:2 profile(Hi422P)、high 4:4:4 profile(Hi444P)4个profile。

  4. H.264 baseline profile、extended profile和main profile都是针对8位样本数据、4:2:0格式的视频序列,FRExt将其扩展到8~12位样本数据,视频格式可以为4:2:0、4:2:2、4:4:4,设⽴了highprofile(HP)、high 10 profile(Hi10P)、high 4:2:2 profile(Hi422P)、high 4:4:4 profile(Hi444P) 4个profile,这4个profile都以main profile为基础。

  5. 在相同配置情况下,High profile(HP)可以⽐Main profile(MP)节省10%的码流量,⽐MPEG-2MP节省60%的码流量,具有更好的编码性能。根据应⽤领域的不同:

    1. baseline profile多应⽤于实时通信领域;
    2. main profile多应⽤于流媒体领域;
    3. high profile则多应⽤于⼴电和存储领域
  6. 扩展阅读:H264编码系列之profile & level控制

  7. 如果你想让你的视频最⼤化的和⽬标播放设备兼容(⽐如⽼版本的的ios或者所有的android 设备),那么你可以这做:

-profile:v baseline
  1. 这将会关闭很多⾼级特性,但是它会提供很好的兼容性。也许你可能不需要这些设置,因为⼀旦你⽤了这些设置,在同样的视频质量下与更⾼的编码档次相⽐会使⽐特率稍有增加。
  2. 关于profile列表和关于它们的描述,你可以运⾏x264 --fullhelp
  3. 要牢记apple quick time 对于x264编码的视频只⽀持 YUV 420颜⾊空间,⽽且不⽀持任何⾼于 mianprofile编码档次。这样对于quick time 只留下了两个兼容选项baseline 和 main。其他的编码档次qucik time均不⽀持,虽然它们均可以在其它的播放设备上回放
4. 问题与解答:
  1. 两遍编码模式能够⽐CRF模式提供更好的质量吗?
    不能,但它可以更加精确地控制⽬标⽂件⼤⼩。
  2. 为什么 placebo 是⼀个浪费时间的玩意⼉?
    与 veryslow相⽐,它以极⾼的编码时间为代价换取了⼤概1%的视频质量提升,这是⼀种收益递减准则,veryslow 与 slower相⽐提升了3%;slower 与 slow相⽐提升了5%;slow 与 medium相⽐提升了5%~10%。
  3. 为什么我的⽆损输出看起来是⽆损的?
    这是由于rgb->yuv的转换,如果你转换到yuv444,它依然是⽆损的。
  4. 显卡能够加速x264的编码吗?
    不,x264没有使⽤(⾄少现在没有),有⼀些私有编码器使⽤了GPU加快了编码速度,但这并不意味着它们经过良好的优化。也有可能还不如x264,或许速度更慢。总的来说,ffmpeg到⽬前为⽌还不⽀持GPU。翻译注释:x264在2013版中已经开始⽀持基于opencl的显卡加速,⽤于帧类型的判定。
  5. 为Quick time 播放器压制视频
    你需要使⽤-pix_fmt yuv420p来是你的输出⽀持QT 播放器。这是因为对于H.264视频剪辑苹果的Quicktime只⽀持 YUV420颜⾊空间。否则ffmpeg会根据你的视频源输出与Quick time 不兼容的视频格式或者不是基于ffmpeg的视频。

4. X264参数之zerolatency的分析

  1. X264参数之zerolatency的分析

5. YUV编码成H.264案例

/**
* @projectName   08-02-encode_video
* @brief         视频编码,从本地读取YUV数据进行H264编码
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libavcodec/avcodec.h>
#include <libavutil/time.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>

int64_t get_time() {
    return av_gettime_relative() / 1000;  // 换算成毫秒
}

static int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                  FILE *outfile) {
    int ret;

    /* send the frame to the encoder */
    if (frame)
        printf("Send frame %3"
    PRId64
    "\n", frame->pts);
    /* 通过查阅代码,使用x264进行编码时,具体缓存帧是在x264源码进行,
     * 不会增加avframe对应buffer的reference*/
    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        return -1;
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        } else if (ret < 0) {
            fprintf(stderr, "Error encoding audio frame\n");
            return -1;
        }

        if (pkt->flags & AV_PKT_FLAG_KEY)
            printf("Write packet flags:%d pts:%3"
        PRId64
        " dts:%3"
        PRId64
        " (size:%5d)\n",
                pkt->flags, pkt->pts, pkt->dts, pkt->size);
        if (!pkt->flags)
            printf("Write packet flags:%d pts:%3"
        PRId64
        " dts:%3"
        PRId64
        " (size:%5d)\n",
                pkt->flags, pkt->pts, pkt->dts, pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
    }
    return 0;
}

/**
 * @brief 提取测试文件:ffmpeg -i test_1280x720.flv -t 5 -r 25 -pix_fmt yuv420p yuv420p_1280x720.yuv
 *           参数输入: yuv420p_1280x720.yuv yuv420p_1280x720.h264 libx264
 * @param argc
 * @param argv
 * @return
 */
int main(int argc, char **argv) {
    char *in_yuv_file = NULL;
    char *out_h264_file = NULL;
    FILE *infile = NULL;
    FILE *outfile = NULL;

    const char *codec_name = NULL;
    const AVCodec *codec = NULL;
    AVCodecContext *codec_ctx = NULL;
    AVFrame *frame = NULL;
    AVPacket *pkt = NULL;
    int ret = 0;

    if (argc < 4) {
        fprintf(stderr, "Usage: %s <input_file out_file codec_name >, argc:%d\n",
                argv[0], argc);
        return 0;
    }
    in_yuv_file = argv[1];      // 输入YUV文件
    out_h264_file = argv[2];
    codec_name = argv[3];

    /* 查找指定的编码器 */
    codec = avcodec_find_encoder_by_name(codec_name);
    if (!codec) {
        fprintf(stderr, "Codec '%s' not found\n", codec_name);
        exit(1);
    }

    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }


    /* 设置分辨率*/
    codec_ctx->width = 1280;
    codec_ctx->height = 720;
    /* 设置time base */
    codec_ctx->time_base = (AVRational) {1, 25};
    codec_ctx->framerate = (AVRational) {25, 1};
    /* 设置I帧间隔
     * 如果frame->pict_type设置为AV_PICTURE_TYPE_I, 则忽略gop_size的设置,一直当做I帧进行编码
     */
    codec_ctx->gop_size = 25;   // I帧间隔
    codec_ctx->max_b_frames = 2; // 如果不想包含B帧则设置为0
    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    //
    if (codec->id == AV_CODEC_ID_H264) {
        // 相关的参数可以参考libx264.c的 AVOption options
        // ultrafast all encode time:2270ms
        // medium all encode time:5815ms
        // veryslow all encode time:19836ms
        ret = av_opt_set(codec_ctx->priv_data, "preset", "medium", 0);
        if (ret != 0) {
            printf("av_opt_set preset failed\n");
        }
        ret = av_opt_set(codec_ctx->priv_data, "profile", "main", 0); // 默认是high
        if (ret != 0) {
            printf("av_opt_set profile failed\n");
        }
        ret = av_opt_set(codec_ctx->priv_data, "tune", "zerolatency", 0); // 直播是才使用该设置
//        ret = av_opt_set(codec_ctx->priv_data, "tune","film",0); //  画质film
        if (ret != 0) {
            printf("av_opt_set tune failed\n");
        }
    }

    /*
     * 设置编码器参数
    */
    /* 设置bitrate */
    codec_ctx->bit_rate = 3000000;
//    codec_ctx->rc_max_rate = 3000000;
//    codec_ctx->rc_min_rate = 3000000;
//    codec_ctx->rc_buffer_size = 2000000;
//    codec_ctx->thread_count = 4;  // 开了多线程后也会导致帧输出延迟, 需要缓存thread_count帧后再编程。
//    codec_ctx->thread_type = FF_THREAD_FRAME; // 并 设置为FF_THREAD_FRAME
    /* 对于H264 AV_CODEC_FLAG_GLOBAL_HEADER  设置则只包含I帧,此时sps pps需要从codec_ctx->extradata读取
     *  不设置则每个I帧都带 sps pps sei
     */
//    codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // 存本地文件时不要去设置

    /* 将codec_ctx和codec进行绑定 */
    ret = avcodec_open2(codec_ctx, codec, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
        exit(1);
    }
    printf("thread_count: %d, thread_type:%d\n", codec_ctx->thread_count, codec_ctx->thread_type);
    // 打开输入和输出文件
    infile = fopen(in_yuv_file, "rb");
    if (!infile) {
        fprintf(stderr, "Could not open %s\n", in_yuv_file);
        exit(1);
    }
    outfile = fopen(out_h264_file, "wb");
    if (!outfile) {
        fprintf(stderr, "Could not open %s\n", out_h264_file);
        exit(1);
    }

    // 分配pkt和frame
    pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }

    // 为frame分配buffer
    frame->format = codec_ctx->pix_fmt;
    frame->width = codec_ctx->width;
    frame->height = codec_ctx->height;
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        exit(1);
    }
    // 计算出每一帧的数据 像素格式 * 宽 * 高
    // 1382400
    int frame_bytes = av_image_get_buffer_size(frame->format, frame->width,
                                               frame->height, 1);
    printf("frame_bytes %d\n", frame_bytes);
    uint8_t *yuv_buf = (uint8_t *) malloc(frame_bytes);
    if (!yuv_buf) {
        printf("yuv_buf malloc failed\n");
        return 1;
    }
    int64_t begin_time = get_time();
    int64_t end_time = begin_time;
    int64_t all_begin_time = get_time();
    int64_t all_end_time = all_begin_time;
    int64_t pts = 0;
    printf("start enode\n");
    for (;;) {
        memset(yuv_buf, 0, frame_bytes);
        size_t read_bytes = fread(yuv_buf, 1, frame_bytes, infile);
        if (read_bytes <= 0) {
            printf("read file finish\n");
            break;
        }
        /* 确保该frame可写, 如果编码器内部保持了内存参考计数,则需要重新拷贝一个备份
            目的是新写入的数据和编码器保存的数据不能产生冲突
        */
        int frame_is_writable = 1;
        if (av_frame_is_writable(frame) == 0) { // 这里只是用来测试
            printf("the frame can't write, buf:%p\n", frame->buf[0]);
            if (frame->buf && frame->buf[0])        // 打印referenc-counted,必须保证传入的是有效指针
                printf("ref_count1(frame) = %d\n", av_buffer_get_ref_count(frame->buf[0]));
            frame_is_writable = 0;
        }
        ret = av_frame_make_writable(frame);
        if (frame_is_writable == 0) {  // 这里只是用来测试
            printf("av_frame_make_writable, buf:%p\n", frame->buf[0]);
            if (frame->buf && frame->buf[0])        // 打印referenc-counted,必须保证传入的是有效指针
                printf("ref_count2(frame) = %d\n", av_buffer_get_ref_count(frame->buf[0]));
        }
        if (ret != 0) {
            printf("av_frame_make_writable failed, ret = %d\n", ret);
            break;
        }
        int need_size = av_image_fill_arrays(frame->data, frame->linesize, yuv_buf,
                                             frame->format,
                                             frame->width, frame->height, 1);
        if (need_size != frame_bytes) {
            printf("av_image_fill_arrays failed, need_size:%d, frame_bytes:%d\n",
                   need_size, frame_bytes);
            break;
        }
        pts += 40;
        // 设置pts
        frame->pts = pts;       // 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率
        begin_time = get_time();
        ret = encode(codec_ctx, frame, pkt, outfile);
        end_time = get_time();
        printf("encode time:%lldms\n", end_time - begin_time);
        if (ret < 0) {
            printf("encode failed\n");
            break;
        }
    }

    /* 冲刷编码器 */
    encode(codec_ctx, NULL, pkt, outfile);
    all_end_time = get_time();
    printf("all encode time:%lldms\n", all_end_time - all_begin_time);
    // 关闭文件
    fclose(infile);
    fclose(outfile);

    // 释放内存
    if (yuv_buf) {
        free(yuv_buf);
    }

    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&codec_ctx);

    printf("main finish, please enter Enter and exit\n");
    getchar();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
|---------H.264encode(h264编码代码) |---------h264的编解码库和头文件,采用ffmpeg和x264编译(h264交叉编译ffmpeg) |--------- H264Player.rar(H264播放器源代码纯C++) |--------- |--------- H264的经典算法优化 |--------- JM H264解码程序 |--------- h264的编解码库和头文件, |--------- 采用ffmpeg和x264编译 h264和mepg4协议标准 |--------- H264流媒体源代码和相关资料.rar9 |--------- h264实时分析工具H264Visa |--------- h264视频采集 |--------- h264相关资料和源代码 |--------- ,decode264是一个使用ffmpeg sdk开发h264解码的例子 |--------- H264资料打包(二) |--------- H264资料打包(一) |--------- x264视频编解码在linux下实现的源码 |--------- [pdf文档] h264中文协议(中英文对照)9 |--------- T-REC-H.264 |--------- H264新手入门(H264乐园聊天记录 |--------- h24-tw(台湾教程) |--------- h264解码之CAVLC编码实例 |--------- h264_encoder(一个最经典的c语言的源代码) |--------- PDFH.264_GraphShow 2.linux_ffmpeg_h264视频音频编码界面(不断更新更新的内容通过邮箱发布)----- |---------linux环境下视频编程流程 |--------- 基于Linux高清视频无线传输系统设计研究 |--------- 基于嵌入式Linux的远程网络视频监控系统 |--------- 基于linux_V4L视频采集摄像程序 |--------- 基于Linux的视频传输系统(完整方案) |---------嵌入式Linux应用开发完全手册视频源码 |---------arm-linux平台的视频监控程序 |---------交叉编译ffmpeg_+_x264_编码H264_(arm_Linux 3.android视频音频_h264_ffmpeg------------------------ |---------JVT-G050 |--------- FFMPEG移植到Android |--------- 视频的源码,很详细并有注释可用于学习 Android视频采集和实现 |--------- ,采用h264视频编码,3gp格式 android中调用FFMPEG4解码方法与so文 |--------- jm15.0 |--------- ffmpeg for android library anroid手机上的一个音视频编解码库 |--------- |--------- 利用Android 浏览器引擎Webkit 加载具有视频监控功能的插件,以此插件为核心模块扩展浏览器的功能,从而实现手机监控 |--------- ffmpeg H264学习指南介绍 |--------- android opencore框架下的视频编码源码实现 android 视频监控的,开启本地摄像机,设置好端口即可 |--------- android 视频实时采集并上传到服务器上 android的视频监视器,捕捉接收远程的监视视频并显示在手机上

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值