FFmpeg———encode_video(学习)

news2024/10/7 14:21:52

目录

  • 前言
  • 源码
  • 函数
  • 最终效果

前言

encode_video:实现了对图片使用指定编码进行编码,生成可播放的视频流,编译时出现了一些错误,做了一些调整。
基本流程:
1、获取指定的编码器
2、编码器内存申请
3、编码器上下文内容参数设置
4、打开编码器
5、申请数据帧内存
6、模拟图片
7、编码

源码

测试代码,做了部分修改

#include <iostream>

using namespace std;


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern"C"
{
#include "libavcodec/avcodec.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/error.h"
}

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

    /* send the frame to the encoder */
    if (frame)
        printf("Send frame %lld\n", frame->pts);  //修改 lld 替换 PRId64

    /*avcodec_send_frame 与 avcodec_receive_packet 配合使用*/
    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }

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

        printf("Write packet %lld (size=%d)\n", pkt->pts, pkt->size); //修改 lld 替换 PRId64
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt); //清空数据压缩包
    }
}

int main()
{
    const char* filename;
    const AVCodec* codec;
    AVCodecContext* c = NULL;  // 编码器上下文
    int i, ret, x, y;
    FILE* f;
    AVFrame* frame;  // 音视频数据帧结构体
    AVPacket* pkt;
    uint8_t endcode[] = { 0, 0, 1, 0xb7 };

    filename = "text_264";

    /* find the mpeg1video encoder */
    codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    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);
    }

    pkt = av_packet_alloc();
    if (!pkt)
        exit(1);

    /* put sample parameters */
    c->bit_rate = 400000;
    /* 分辨率 为2的倍数 */
    c->width = 352;
    c->height = 288;
    /* frames per second */
    c->time_base.num = 1;
    c->time_base.den = 25;

    //帧率
    c->framerate.num = 25;
    c->framerate.den = 1;


    /* emit one intra frame every ten frames
     * check frame pict_type before passing frame
     * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
     * then gop_size is ignored and the output of encoder
     * will always be I frame irrespective to gop_size
     */
    c->gop_size = 10;
    c->max_b_frames = 1;  //非B帧之间的最大的B帧数
    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 */
    ret = avcodec_open2(c, codec, NULL);
    if (ret < 0) {

        fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
        exit(1);
    }

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }

    frame = av_frame_alloc();
    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;

    ret = av_frame_get_buffer(frame, 0);  //申请数据帧缓冲区
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        exit(1);
    }

    /* encode 1 second of video */
    for (i = 0; i < 25; i++) {
        fflush(stdout);

        /* Make sure the frame data is writable.
           On the first round, the frame is fresh from av_frame_get_buffer()
           and therefore we know it is writable.
           But on the next rounds, encode() will have called
           avcodec_send_frame(), and the codec may have kept a reference to
           the frame in its internal structures, that makes the frame
           unwritable.
           av_frame_make_writable() checks that and allocates a new buffer
           for the frame only if necessary.
         */
        ret = av_frame_make_writable(frame);    //确保数据帧是可写
        if (ret < 0)
            exit(1);

        /* 
        模拟图片数据
         */
         /* 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 */
        encode(c, frame, pkt, f);
    }

    /* flush the encoder */
    encode(c, NULL, pkt, f);

    /* Add sequence end code to have a real MPEG file.
       It makes only sense because this tiny examples writes packets
       directly. This is called "elementary stream" and only works for some
       codecs. To create a valid file, you usually need to write packets
       into a proper file format or protocol; see mux.c.
     */
    if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)
        fwrite(endcode, 1, sizeof(endcode), f);
    fclose(f);

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

    return 0;
}

函数

1、int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
向编码器发送音频或视频的数据包与
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);配合使用
成功返回0
2、av_err2str(errnum)
编译会报错
修改:

char av_error[AV_ERROR_MAX_STRING_SIZE] = { 0 };
#define av_err2str(errnum) \
    av_make_error_string(av_error, AV_ERROR_MAX_STRING_SIZE, errnum)

最终效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1649009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧公厕:数据驱动的新时代公共厕所管理

公共厕所是城市的重要基础设施&#xff0c;直接关系到人民群众的生活质量和城市形象。然而&#xff0c;长期以来&#xff0c;公共厕所的管理问题一直困扰着城市管理者。为了解决这个难题&#xff0c;智慧公厕应运而生。本文将以智慧公厕源头实力厂家广州中期科技有限公司&#…

商务分析方法与工具(四):Python的趣味快捷-简单函数你真的会用吗?

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

CDN内容分发网络

CDN&#xff1a;内容分发网络的起源与工作原理 随着互联网的迅猛发展&#xff0c;内容交付网络&#xff08;CDN&#xff09;作为一种重要的网络基础设施&#xff0c;扮演着越来越关键的角色。本文将从CDN的起源、简介、工作原理以及如何识别等方面进行阐述。 # 1. CDN的起源 …

想做视频号小店,为何不建议开通个体店?开店步骤+做店思路如下

我是王路飞。 如果你想在视频号开通店铺的话&#xff0c;那么一定不要使用个体执照开通个体店&#xff1f; 这是为什么呢&#xff1f; 原因很简单&#xff0c;视频号个体店是无法入驻优选联盟的&#xff0c;只能企业店可以入驻。 因为现阶段视频号小店的自然流量很少&#…

elementUI table表格相同元素合并行----支持多列

效果图如下: vue2代码如下&#xff1a; 只粘贴了js方法哦&#xff0c; methods: {// 设置合并行 setrowspans() { const columns [‘name’, ‘value’]; // 需要合并的列名 // 为每个需要合并的列设置默认 rowspan this.tableData.forEach(row > { columns.forEach(col …

flutter开发实战-GetX响应式状态管理使用

flutter开发实战-GetX响应式状态管理使用 GetX是一个简单的响应式状态管理解决方案。GetX是Flutter的一款超轻、功能强大的解决方案。它将高性能状态管理、智能依赖注入和路由管理快速而实用地结合在一起。这里简单使用一下GetX 一、引入GetX 在工程的pubspec.yaml中引入插件…

药物代谢动力学学习笔记

一、基本概念 二、经典房室模型 三、非线性药物代谢动力学 四、非房室模型 五、药代动力学与药效动力学 六、生物等效性评价 七、生物样品分析方法 基本概念 生物样品&#xff1a;生物机体的全血、血浆、血清、粪便、尿液或其他组织的样品 特异性&#xff0c;specificity&…

运维实施工程师之Linux服务器全套教程

一、Linux目录结构 1.1 基本介绍 Linux 的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录“/”&#xff0c;然后在此目录下再创建其他的目录。 在 Linux 世界里&#xff0c;一切皆文件&#xff08;即使是一个硬件设备&#xff0c;也是使用文本来标…

MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE

欢迎阅读 MQTT 5.0 报文系列 的第三篇文章。在上一篇中&#xff0c;我们介绍了 MQTT 5.0 的 PUBLISH 及其响应报文。现在&#xff0c;我们将介绍用于订阅和取消订阅的控制报文。 在 MQTT 中&#xff0c;SUBSCRIBE 报文用于发起订阅请求&#xff0c;SUBACK 报文用于返回订阅结果…

纯干货!Prompt链式方法总结,灵活驾驭各种大模型!

当面对复杂任务的时&#xff0c;单一的Prompt是不够的&#xff0c;我们需要将Prompt链接在一起才能完成。今天这篇文章主要集中在Prompt链式方法介绍用于实现复杂任务生成&#xff0c;其中主要包括&#xff1a;顺序Prompt链、并行Prompt链、抽样Prompt链、树状Prompt链、循环Pr…

SpringBoot实现Config下自动关联.xml、.properties配置信息的实例教程

本篇文章主要讲解在SpringBoot实现Config下自动关联.xml、.properties配置信息的实例教程。 日期&#xff1a;2024年5月4日 作者&#xff1a;任聪聪 .properties文件调用方法 步骤一、打开我们的 .properties 创建一个demo参数如下图&#xff1a; 步骤二、创建一个config的包&…

代码随想录——双指针与滑动窗口(四)

一.1423. 可获得的最大点数 题目详情 解题思路 这里我们每次只能取最左或最右边的卡牌,第一反应其实是使用双指针&#xff0c;通过局部贪心来解决&#xff0c;但是如果两边相等的话用局部贪心无法来判断到底取哪一边&#xff0c;那我们不妨换一个思路&#xff1a; 我们首先任…

uniapp的app端推送功能,不使用unipush

1&#xff1a;推送功能使用htmlPlus实现&#xff1a;地址HTML5 API Reference (html5plus.org) 效果图&#xff1a; 代码实现&#xff1a; <template><view class"content"><view class"text-area"><button click"createMsg&q…

Echarts柱状图横坐标不显示

本人遇到的问题&#xff1a;折线图横坐标可以正常显示 柱状图接收一样的数据在横坐标却显示不了 1.在前端打印是否能够正常接收数据、数据类型是否有误以及数据是否有内容 console.log(typeof optionbar.xAxis.data)console.log(optionbar.xAxis.data) 2.如上确定能够接收到数…

1天搞定SpringBoot+Vue全栈开发 (6)组件化开发

1.NPM使用 2.Vue CLI使用 3.组件化开发 修改App.vue&#xff1a; <template><img alt"Vue logo" src"./assets/logo.png" /><Hello></Hello> </template><script> import Hello from "./components/Hello.vue&q…

2-5 任务:打印九九表

本次实战的目标是通过编写程序实现打印九九乘法表、字符矩形、字符平行四边形和字符菱形等图形&#xff0c;以及解决百钱买百鸡问题和输出素数等实际问题。在实战过程中&#xff0c;我们将学习并掌握以下知识点。 双重循环的使用&#xff1a;通过双重循环实现九九乘法表的打印&…

Vector Laboratories|用于生物偶联疗法BioDesign™ dPEG® Linker连接平台

术语dPEG代表“离散PEG&#xff08;discrete PEG&#xff09;”&#xff0c;这是一种均一的、单分子量&#xff08;MW&#xff09;、高纯度的新一代聚乙二醇聚合物。Vector Laboratorie采用其受专利保护的专有生产工艺&#xff0c;可生产提供适合于各种应用场景&#xff0c;具有…

3月PMP成绩已公布!(附查询流程)

2024年3月PMP考试成绩已出~宝子们抓紧时间查询&#xff0c;没查到的也不要着急&#xff0c;在一周内考试成绩都会以邮件的形式通知给大家~ 下面查询PMP成绩的流程给大家安排上~↓↓↓ 方式一&#xff1a;直接登陆官网查询 1、查询网址&#xff1a;PMI官网&#xff1a;www.pmi.…

【贪心算法】单源最短路径Python实现

文章目录 [toc]问题描述Dijkstra算法Dijkstra算法的正确性贪心选择性质最优子结构性质 Dijkstra算法应用示例Python实现时间复杂性 问题描述 给定一个带权有向图 G ( V , E ) G (V , E) G(V,E)&#xff0c;其中每条边的权是非负实数&#xff0c;给定 V V V中的一个顶点&…

Hive3.0新特性:Materialized Views 物化视图

Materialized Views 物化视图 在 Apache Hive 3.0 中引入了物化视图&#xff08;Materialized Views&#xff09;的支持&#xff0c;它们是预先计算并缓存了查询结果的数据结构&#xff0c;以提高查询性能和降低延迟。物化视图通过将查询的结果存储在物理表中来实现&#xff0…