FFmpeg———encode_video(学习)

目录

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

前言

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)

最终效果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

平平科技工作室-Python-超级玛丽

一.准备图片 放在文件夹取名为images 二.准备一些音频和文字格式 放在文件夹media 三.编写代码 import sys, os sys.path.append(os.getcwd()) # coding:UTF-8 import pygame,sys import os from pygame.locals import* import time pygame.init() # 设置一个长为1250,宽为…

03.配置监控一台服务器主机

配置监控一台服务器主机 安装zabbix-agent rpm -ivh https://mirror.tuna.tsinghua.edu.cn/zabbix/zabbix/4.0/rhel/7/x86_64/zabbix-agent-4.0.11-1.el7.x86_64.rpm配置zabbix-agent,配置的IP地址是zabbix-server的地址&#xff0c;因为要监控这台主机 vim /etc/zabbix/zab…

淘宝线上扭蛋机小程序:推动扭蛋机销量

扭蛋机作为一个新兴的娱乐消费模式&#xff0c;能够带给消费者“盲盒式”的消费乐趣&#xff0c;正在快速发展中。消费者通过投币、扫码支付等&#xff0c;在机器上扭下按钮就可以随机获得一个扭蛋商品&#xff0c;这些商品也包括动漫衍生周边、IP主题商品等&#xff0c;种类多…

先电2.4的openstack搭建

先电2.4版本的openstack&#xff0c;前期虚拟机部署参考上一篇2.2版本&#xff0c;基本步骤是一样的&#xff0c;准备两个镜像文件CentOS-7.5-x86_64-DVD-1804.iso&#xff0c;XianDian-IaaS-V2.4.iso [rootcontroller ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno16777…

新手开抖店多久可以出单?做好这两点!七天必出单!

哈喽~我是电商月月 很多新手开抖店长时间不出单&#xff0c;觉得不正常&#xff0c;害怕新手根本做不起来店&#xff0c;就会搜索&#xff1a;新手开抖店多久可以出单&#xff1f; 新手开店&#xff0c;合理运营的话&#xff0c;七天里肯定是能出几单的&#xff0c;但没做好的…

AI新突破:多标签预测技术助力语言模型提速3倍

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; 引言&#xff1a;多标签预测的新视角 在人工智能领域&#xff0c;尤其是在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;预测模型的训练方法一直在…

Android(一)

坏境 java版本 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 进入安卓官网下载 勾选协议 next 如果本地有设置文件&#xff0c;选择Config or installation folder 如果本地没有设置文件&#xff0c;选择Do not import settings 同意两个协议 耐…

Android 14 init进程解析

前言 当bootloader启动后&#xff0c;启动kernel&#xff0c;kernel启动完后&#xff0c;在用户空间启动init进程&#xff0c;再通过init进程&#xff0c;来读取init.rc中的相关配置&#xff0c;从而来启动其他相关进程以及其他操作。 init进程启动主要分为两个阶段&#xff1…

张大哥笔记:卖盗版网课,获利 100 万被抓

这几天刷视频&#xff0c;看到一个新闻&#xff0c;某大学生卖盗版网课&#xff0c;把别人2000多正版网课&#xff0c;以做活动名义售卖20元&#xff0c;获利100多万被抓。 下方图片来自&#xff1a;极目新闻 卖这种盗版网课&#xff0c;门槛低&#xff0c;成本低&#xff0c;…

win中python中OpenCV使用cv2.imshow()报错的解决办法

1. 问题 cv2.error: OpenCV(4.9.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:1272: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK 2.x or Cocoa support. If you are on Ubuntu o…

Python实现SMA黏菌优化算法优化循环神经网络回归模型(LSTM回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 黏菌优化算法&#xff08;Slime mould algorithm&#xff0c;SMA&#xff09;由Li等于2020年提出&…

汉之名将韩信

与英勇霸气的项羽相比&#xff0c;刘邦或许显得无能猥琐&#xff0c;但刘邦深知自己的不足&#xff0c;愿意放权给跟随他的人&#xff0c;让他们发挥才能。正是这种谦逊和智慧&#xff0c;最终让刘邦赢得了天下。 帷帐之间筹谋&#xff0c;千里之外决胜&#xff0c;我之子房无…

计算机服务器中了halo勒索病毒怎么处理,halo勒索病毒解密流程步骤

在网络技术飞速发展的时代&#xff0c;越来越多的企业走向了数字化办公模式&#xff0c;利用网络可以开展各项工作业务&#xff0c;网络也为企业的生产运营提供了极大便利&#xff0c;但网络是一把双刃剑&#xff0c;从网络出现就一直存在网络数据安全问题&#xff0c;这也是众…

Essential Input and Output

How to read data from the keyboard? How to format data for output on the screen? How to deal with character output? 一、Input from the Keyboard the scanf_s() function that is the safe version of scanf() int scanf_s(const char * restrict format, ... );…

电子电器架构 --- 主机厂产线的两种刷写方法

电子电器架构 — 主机厂产线的两种刷写方法 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证…

【Django学习笔记(六)】MySQL的安装配置、启动关闭操作

MySQL的安装配置、启动关闭操作 前言正文1、初识网站1.1 实现静态网站与动态网站效果1.2 数据存储方式 2、MySQL的安装和配置2.1 MySQL下载2.2 安装补丁2.3 安装MySQL2.4 创建配置文件2.5 初始化 3、MySQL的启动和关闭4、MySQL连接测试4.1 MySQL 的连接方式4.2 使用 MySQL自带工…

【muduo源码学习】源码分析之Channel、EventLoop和Selector

在 one-loop-per-thread核心原理 中&#xff0c;介绍了 one loop per thread 网络模型的核心原理&#xff0c;在本篇本章中&#xff0c;我将重点介绍该模型中的IO事件处理部分在 muduo 网络库中是如何实现的&#xff0c;而涉及 TCP 连接处理部分&#xff0c;也即 socket 编程部…

群发邮件软件哪个好

选择一个好的群发邮件软件取决于您的具体需求&#xff0c;如预算、邮件量、自动化需求、分析深度以及是否需要集成其他营销工具等。以下是一些评价较高且功能强大的群发邮件软件&#xff0c;您可以根据自身情况选择&#xff1a; 易邮件群发大师&#xff1a;一款传统使用最广泛的…

【项目学习01_2024.05.05_Day05】

学习笔记 4.3 接口开发4.3.1 树型表查询4.3.2 开发Mapper4.3.3 开发Service4.3.4 测试Service 4.4 接口测试4.4.1 接口层代码完善4.4.2 测试接口 4.3 接口开发 4.3.1 树型表查询 4.3.2 开发Mapper 在对应的Mapper里定义一个方法 在同名的xml文件里具体定义相应的sql语句 4…

阿里实习生:面试阿里其实并没有那么难。

愉快的五一假期已经结束了, 又要投入到学习和工作当中了。 今天分享一位同学在阿里的Go后端实习面经详解, 希望对你有帮助。 Go里有哪些数据结构是并发安全的&#xff1f; 并发安全就是程序在并发的情况下执行的结果都是正确的&#xff1b; Go中数据类型分为两大类&#xff…