FFmpeg H264增加SEI

先看使用场景:
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;
}

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值