技术标签: H264 SEI FFMPEG FFMPEG
先看使用场景:
https://blog.csdn.net/lsheevyfg/article/details/80951415
https://www.jianshu.com/p/4d9120dfcd69
参考文章:
https://blog.csdn.net/ab7936573/article/details/74135909
FFMPEG使用版本为3.2.2
直接上代码:
EvHeade.h
#ifdef __cplusplus
extern "C"
{
#endif
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libavutil\avutil.h"
#ifdef __cplusplus
}
#endif
#ifdef _WIN32
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avdevice.lib")
#pragma comment(lib,"avfilter.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"postproc.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")
#endif
sei_packet.h
#ifndef SEI_PACKET_H
#define SEI_PACKET_H
#include <stdint.h>
uint32_t reversebytes(uint32_t value);
uint32_t get_sei_packet_size(uint32_t size);
int fill_sei_packet(unsigned char * packet, bool isAnnexb, const char * content, uint32_t size);
int get_sei_content(unsigned char * packet, uint32_t size, char * buffer, int *count);
#pragma once
#endif
sei_packet.cpp
#include "sei_packet.h"
#include <stdio.h>
#include <string.h>
#define min(X,Y) ((X) < (Y) ? (X) : (Y))
#define UUID_SIZE 16
//FFMPEG uuid
//static unsigned char uuid[] = { 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef };
//self UUID
static unsigned char uuid[] = {
0x54, 0x80, 0x83, 0x97, 0xf0, 0x23, 0x47, 0x4b, 0xb7, 0xf7, 0x4f, 0x32, 0xb5, 0x4e, 0x06, 0xac };
//开始码
static unsigned char start_code[] = {
0x00,0x00,0x00,0x01};
uint32_t reversebytes(uint32_t value) {
return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}
uint32_t get_sei_nalu_size(uint32_t content)
{
//SEI payload size
uint32_t sei_payload_size = content + UUID_SIZE;
//NALU + payload类型 + 数据长度 + 数据
uint32_t sei_size = 1 + 1 + (sei_payload_size / 0xFF + (sei_payload_size % 0xFF != 0 ? 1 : 0)) + sei_payload_size;
//截止码
uint32_t tail_size = 2;
if (sei_size % 2 == 1)
{
tail_size -= 1;
}
sei_size += tail_size;
return sei_size;
}
uint32_t get_sei_packet_size(uint32_t size)
{
return get_sei_nalu_size(size) + 4;
}
int fill_sei_packet(unsigned char * packet,bool isAnnexb, const char * content, uint32_t size)
{
unsigned char * data = (unsigned char*)packet;
unsigned int nalu_size = (unsigned int)get_sei_nalu_size(size);
uint32_t sei_size = nalu_size;
//大端转小端
nalu_size = reversebytes(nalu_size);
//NALU开始码
unsigned int * size_ptr = &nalu_size;
if (isAnnexb)
{
memcpy(data, start_code, sizeof(unsigned int));
}
else
{
memcpy(data, size_ptr, sizeof(unsigned int));
}
data += sizeof(unsigned int);
unsigned char * sei = data;
//NAL header
*data++ = 6; //SEI
//sei payload type
*data++ = 5; //unregister
size_t sei_payload_size = size + UUID_SIZE;
//数据长度
while (true)
{
*data++ = (sei_payload_size >= 0xFF ? 0xFF : (char)sei_payload_size);
if (sei_payload_size < 0xFF) break;
sei_payload_size -= 0xFF;
}
//UUID
memcpy(data, uuid, UUID_SIZE);
data += UUID_SIZE;
//数据
memcpy(data, content, size);
data += size;
//tail 截止对齐码
if (sei + sei_size - data == 1)
{
*data = 0x80;
}
else if (sei + sei_size - data == 2)
{
*data++ = 0x00;
*data++ = 0x80;
}
return true;
}
int get_sei_buffer(unsigned char * data, uint32_t size, char * buffer, int *count)
{
unsigned char * sei = data;
int sei_type = 0;
unsigned sei_size = 0;
//payload type
do {
sei_type += *sei;
} while (*sei++ == 255);
//数据长度
do {
sei_size += *sei;
} while (*sei++ == 255);
//检查UUID
if (sei_size >= UUID_SIZE && sei_size <= (data + size - sei) &&
sei_type == 5 && memcmp(sei, uuid, UUID_SIZE) == 0)
{
sei += UUID_SIZE;
sei_size -= UUID_SIZE;
if (buffer != NULL && count != NULL)
{
if (*count > (int)sei_size)
{
memcpy(buffer, sei, sei_size);
}
}
if (count != NULL)
{
*count = sei_size;
}
return sei_size;
}
return -1;
}
int get_sei_content(unsigned char * packet, uint32_t size,char * buffer,int *count)
{
unsigned char ANNEXB_CODE_LOW[] = {
0x00,0x00,0x00,0x01 };
unsigned char ANNEXB_CODE[] = {
0x00,0x00,0x00,0x01 };
unsigned char *data = packet;
bool isAnnexb = false;
if ((size > 3 && memcmp(data, ANNEXB_CODE_LOW,3) == 0) ||
(size > 4 && memcmp(data, ANNEXB_CODE,4) == 0)
)
{
isAnnexb = true;
}
//暂时只处理MP4封装,annexb暂为处理
if (isAnnexb)
{
while (data < packet + size) {
if ((packet + size - data) > 4 && data[0] == 0x00 && data[1] == 0x00)
{
int startCodeSize = 2;
if (data[2] == 0x01)
{
startCodeSize = 3;
}
else if(data[2] == 0x00 && data[3] == 0x01)
{
startCodeSize = 4;
}
if (startCodeSize == 3 || startCodeSize == 4)
{
if ((packet + size - data) > (startCodeSize + 1) &&
(data[startCodeSize] & 0x1F) == 6)
{
//SEI
unsigned char * sei = data + startCodeSize + 1;
int ret = get_sei_buffer(sei, (packet + size - sei), buffer, count);
if (ret != -1)
{
return ret;
}
}
data += startCodeSize + 1;
}
else
{
data += startCodeSize + 1;
}
}
else
{
data++;
}
}
}
else
{
//当前NALU
while (data < packet + size) {
//MP4格式起始码/长度
unsigned int *length = (unsigned int *)data;
int nalu_size = (int)reversebytes(*length);
//NALU header
if ((*(data + 4) & 0x1F) == 6)
{
//SEI
unsigned char * sei = data + 4 + 1;
int ret = get_sei_buffer(sei, min(nalu_size,(packet + size - sei)),buffer,count);
if (ret != -1)
{
return ret;
}
}
data += 4 + nalu_size;
}
}
return -1;
}
文章浏览阅读2.4k次。ASP.NET MVC 的核心设计信条之一是DRY: "不要重复自己(DRY --Don’t Repeat Yourself)"。ASP.NET MVC鼓励您指定功能或者行为,只做一次,然后将它应用到应用程序的各个地方。这可以减少您需要编写的代码量,并减少代码出错率,易于代码维护。给ASP.NET MVC 和 Entity Framework Code First 提供验证支持是 DRY 信条的一次伟大实践。您可以在一个地方 (模型类) 中以声明的方式指定验证规则,这个规则会在应用程序中的任何地方执行。_.net模型验证枚举类型
文章浏览阅读4k次。写好了一个正常的properties文件,然后使用 thymeleaf在页面进行取值结果:??user.name_zh_CN??这是为什么呢,原来这里的properties文件名必须是messages,这是spring boot规定的国际化文件名..._thymeleaf国际化#{login.test}读不到配置文件
文章浏览阅读9.6k次,点赞6次,收藏23次。算法描述: 方案二:递推公式结果:y(1)=0.212647 y(2)=0.071838 y(3)=0.065374 y(4)=0.046157 y(5)=0.038461 y(6)=0.032051 y(7)=0.027701 y(8)=0.02432..._误差传递可以用什么软件计算
文章浏览阅读1.8k次,点赞6次,收藏44次。fastjson是阿里的一款对Json处理的工具,使用前需要引入对应的jar包下载地址本人感觉还是非常强悍的,比Gson使用起来更加的强大package json;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import com...._fastjson tojson
文章浏览阅读1.2k次。前言有时候我们导出的dll仅仅想导出一些函数声明,然后有其他dll进行实现,我们成这里导出声明为:导出函数转发https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160# pragram comment_#pragma comment(linker, "/export
文章浏览阅读1.8k次。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <link rel="icon" href="../../../img/sup.ico" type="image/x-ioc"/&..._用jquery写tab选项卡
文章浏览阅读402次。版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/sjz64472418/article/details/8517182MQ集群及网关队列管理器的搭建描述:如上图所示,为MQ的集群搭建部署图。CLUSTERA、CLUSTERB分别是两个集群,其中Qm1-Qm3、Ga..._amq3681e: ha 子系统已在管理复制的数据队列管理器“gwo.qm”
文章浏览阅读4.6k次,点赞2次,收藏2次。视图并不在数据库中实际存在,行和列数据来自定义视图的查询总使用的表,并且是在使用视图时动态生成的。安全:使用视图的用户只能访问他们被允许的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。简单:使用视图的用户完全不需要关系后面对应的表结构、关联条件和筛选条件,对用户来说已经是过滤好的符合条件的结果集。2.视图不是表,不保存数据,只是一张虚拟的表,源表的数据发生变化后,视图的结果也同步发生变化。视图的可更新性和视图中查询的定义有关系,一下类型的视图是不可更新的。_数据库修改”视图数据,将职工“w010”与客户“c110”签订合同的金额从16万修改为1
文章浏览阅读289次。错误内容:java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zo_mysql 5.7 createsqlexception(sqlerror.java:120) ~[mysql-connector-j-8.0.32.j
文章浏览阅读742次,点赞2次,收藏2次。之前学习C++面向对象编程,只知道构造函数是创建实例对象时被自动调用;然后陆续看了一些书,知识点比较分散,现对构造函数进行一个全面总结,以便更加深入理解构造函数。目录 构造函数是什么? 构造函数形式? 默认构造函数 构造函数初始化列表1.构造函数是什么?构造函数:类中通过一个或者多个特殊的成员函数来控制其对象初始化过程。构造函数的任务是初始化类中的数据成员,无论何..._在面向对象的编程中,什么是构造函数
文章浏览阅读1.6k次。给中国学生的第七封信:21世纪最需要的7种人才人才的标准从来都不是一成不变的。在东方的战国时代和西方的骑士时代里,最受器重的是力敌万夫的勇士和巧舌善辩的谋臣;在中国的科举时代里,靠着“死记硬背”和“八股文章”而金榜题名的书生最容易出人头地;在西方工业革命风起云涌的日子里,善于用机器的力量改变世界的发明家以及那些精通专业、埋头苦干的工程师成了所有人才中的佼佼者;即便是在刚刚过去的20世纪中,_从死记硬背 到 融会贯通 几重境界
文章浏览阅读1.4k次。转自 http://kingj.iteye.com/blog/1558869Objective-C是苹果软件的编程语言,想要上机学习、调试,有一个集成开发环境(IDE)方便很多。有三类方法搭建Objective-C的集成开发环境:1) 使用苹果的平台,集成开发环境使用Xcode。但如果没有苹果平台,想在Windows环境下学习Objective-C,可以采用以下两种方法:_vs code 支持 object-c 语法