将实时h264封装flv后播放有时间但是一直黑屏,有哪位大佬能指导一二!
/*
* FLV muxer
* Copyright (c) 2003 The FFmpeg Project
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include <typeinfo>
#include <unistd.h>
#include <boost/asio.hpp>
#include "client_ws.hpp"
#include "flv.h"
#undef NDEBUG
#include <assert.h>
using namespace std;
using WsClient = SimpleWeb::SocketClient<SimpleWeb::WS>;
double m_DTS=0.0;
/************************************************************/
TagHeader m_tagHeader; //tag头信息
NAL m_nal; //存储NAL单元
void saveH264File(unsigned char* pBuffer, int dwBufSize)
{
FILE * fpVideo;
fpVideo = fopen("444.flv", "ab+"); //以只读二进制方式打开文件
if (!fpVideo)
{
printf("ERROR:open file failed!");
}
int pos = 0;
fwrite(pBuffer, 1, dwBufSize, fpVideo);
fclose(fpVideo);
}
void PrintBuffer(void* pBuff, unsigned int nLen)
{
if (NULL == pBuff || 0 == nLen)
{
return;
}
const int nBytePerLine = 16;
unsigned char* p = (unsigned char*)pBuff;
char szHex[3*nBytePerLine+1] = {0};
unsigned int i;
printf("-----------------begin-------------------\n");
for (i=0; i<nLen; ++i)
{
int idx = 3 * (i % nBytePerLine);
if (0 == idx)
{
memset(szHex, 0, sizeof(szHex));
}
#ifdef WIN32
sprintf_s(&szHex[idx], 4, "%02x ", p[i]);// buff长度要多传入1个字节
#else
snprintf(&szHex[idx], 4, "%02x ", p[i]); // buff长度要多传入1个字节
#endif
// 以16个字节为一行,进行打印
if (0 == ((i+1) % nBytePerLine))
{
printf("%s\n", szHex);
}
}
// 打印最后一行未满16个字节的内容
if (0 != (nLen % nBytePerLine))
{
printf("%s\n", szHex);
}
printf("------------------end-------------------\n");
}
void setFlvHeader()
{
FlvHeader m_flvHeader; //flv头信息
m_flvHeader.signature[0] = 'F';
m_flvHeader.signature[1] = 'L';
m_flvHeader.signature[2] = 'V';
m_flvHeader.version = 0x01;
m_flvHeader.present = 0;
m_flvHeader.present |= 0x01;
m_flvHeader.size[0] = 0x00;
m_flvHeader.size[1] = 0x00;
m_flvHeader.size[2] = 0x00;
m_flvHeader.size[3] = 0x09;
saveH264File(m_flvHeader.data, 9);
//printf("1: ");
//PrintBuffer(m_flvHeader.data, 9);
}
/* 写第一个Tag Size */
void writeFirstTagSize()
{
unsigned char data[4] = {0x00,0x00,0x00,0x00};
saveH264File(data, 4);
//printf("写第一个Tag Size2: ");
//PrintBuffer(data, 4);
}
/* 写前一个Tag Size */
void writePreTagSize()
{
FILE * fpVideo;
fpVideo = fopen("444.flv", "ab+"); //以只读二进制方式打开文件
unsigned char data[4] = {0x00,0x00,0x00,0x00};
unsigned int length = m_tagHeader.getSize();
data[3] = (unsigned char)(length&0xFF); length = length>>8;
data[2] = (unsigned char)(length&0xFF); length = length>>8;
data[1] = (unsigned char)(length&0xFF); length = length>>8;
data[0] = (unsigned char)(length&0xFF); length = length>>8;
PrintBuffer(data, 4);
saveH264File(data, 4);
//printf("前一个Tag Size3: ");
//cout << "前一个Tag: " << length << endl;
//PrintBuffer(data, 4);
//fwrite(data,4,1,fpVideo);
//fclose(fpVideo);
}
/*设置Tag头信息*/
void setTagHeader(unsigned char tagType, unsigned int timestamp)
{
memset(m_tagHeader.data,0,11);
m_tagHeader.tagType = tagType;
m_tagHeader.timestamp[2] = (unsigned char)(timestamp&0xFF); timestamp = timestamp>>8;
m_tagHeader.timestamp[1] = (unsigned char)(timestamp&0xFF); timestamp = timestamp>>8;
m_tagHeader.timestamp[0] = (unsigned char)(timestamp&0xFF); timestamp = timestamp>>8;
m_tagHeader.timestamp[3] = (unsigned char)(timestamp&0xFF); timestamp = timestamp>>8;
//printf("设置Tag头信息4: ");
//PrintBuffer(m_tagHeader.data, 11);
}
/*设置Tag数据长度*/
void setTagHeaderDataSize(unsigned int datasize)
{
m_tagHeader.datasize[2] = (unsigned char)(datasize&0xFF); datasize = datasize>>8;
m_tagHeader.datasize[1] = (unsigned char)(datasize&0xFF); datasize = datasize>>8;
m_tagHeader.datasize[0] = (unsigned char)(datasize&0xFF); datasize = datasize>>8;
}
void writeTagHeader()
{
saveH264File(m_tagHeader.data, 11);
//printf("写入Tag Header5: ");
//PrintBuffer(m_tagHeader.data, 11);
}
//写MetaData信息
void writeMetaData()
{
setTagHeader(TAGTYPE_META,0);
/*unsigned char data[135] = {
0x02,0x00,0x0a,0x6f,0x6e,0x4d,0x65,0x74,0x61,0x44,
0x61,0x74,0x61,0x08,0x00,0x00,0x00,0x07,0x00,0x08,
0x64,0x75,0x72,0x61,0x74,0x69,0x6f,0x6e,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x77,
0x69,0x64,0x74,0x68,0x00,0x40,0x9e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x06,0x68,0x65,0x69,0x67,0x68,
0x74,0x00,0x40,0x90,0xe0,0x00,0x00,0x00,0x00,0x00,
0x00,0x09,0x66,0x72,0x61,0x6d,0x65,0x72,0x61,0x74,
0x65,0x00,0x40,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0c,0x76,0x69,0x64,0x65,0x6f,0x63,0x6f,0x64,
0x65,0x63,0x69,0x64,0x00,0x40,0x1c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x08,0x66,0x69,0x6c,0x65,0x73,
0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x09
};*/
unsigned char data[8] = {0x02,0x00,0x05,0x58,0x49,0x41,0x4F,0x43};
setTagHeaderDataSize(8);
writeTagHeader();
//printf("6: ");
//PrintBuffer(data, 135);
saveH264File(data, 8);
/* 写前一个Tag Size */
writePreTagSize();
}
//检查NAL起始符 并返回起始符长度
int checkStartecode(unsigned char data[4],unsigned char pos)
{
if(data[pos]!=0x01) return 0;
for(int i = 0; i<2; i++)
{
unsigned char pos2 = (pos + 4 - 1)%4;
if(data[pos2]!=0x00) return 0;
pos--;
}
unsigned char pos3 = (pos + 4 - 1)%4;
if(data[pos3] == 0x00)
{
return 4;
}
else
{
return 3;
}
}
//读取NAL单元
bool readNal(unsigned char* packetData, int size)
{
unsigned char start[4] = {0xFF,0xFF,0xFF,0xFF};
unsigned char data[4] = {0xFF,0xFF,0xFF,0xFF};
unsigned char pos = 0;
unsigned char d;
//读取起始符
//fread(start,1,4,g_h264_file);
if(packetData[0] == 0x00 && packetData[1] == 0x00)
{
if(packetData[2]== 0x01)
{
m_nal.startcodesize = 3;
}
else if(packetData[2] == 0x00)
{
if(packetData[3] == 0x01)
{
//cout << "关键帧" << endl;
m_nal.startcodesize = 4;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
memcpy(m_nal.payload,packetData,size);
m_nal.size = size; //copy到nal单元中
return true;
}
/* 封装 SPS PPS */
void encapsulateSPSPPS()
{
cout << "11111" << endl;
FILE * fpVideo;
fpVideo = fopen("444.flv", "ab+"); //以只读二进制方式打开文件
if (!fpVideo)
{
printf("ERROR:open file failed!");
}
unsigned char *sps = (unsigned char*)malloc(m_nal.size);
unsigned int spsSize = 29;
memcpy(sps,m_nal.payload,29);
/*if(!readNal())
{
free(sps);
printf("SPS after must be PPS\n");
return;
}*/
//cout << "next: " << endl;
//PrintBuffer(sps, spsSize);
//sleep(10);
//PrintBuffer(m_nal.payload, m_nal.size);
//m_nal.nalType = (m_nal.payload[m_nal.startcodesize]&0x1F);//获取NAL类型
m_nal.nalType = (m_nal.payload[33]&0x1F);
//printf("Tpey: %02x\n", m_nal.payload[33]&0x1F);
//sleep(1);
if(m_nal.nalType != NAL_PPS)
{
printf("SPS after must be PPS\n");
}
setTagHeaderDataSize(spsSize - m_nal.startcodesize + 8 - m_nal.startcodesize + 5 + 11);//注意11是AVconfiguration数据长度
writeTagHeader();
unsigned char data[6] = {0x17,0x00,0x00,0x00,0x00,0x01};//关键帧 H264 AVC sequence header Composition time offset = 00 00 00 configurationVersion 0x01
fwrite(data,6,1,fpVideo);
fwrite(sps + m_nal.startcodesize + 1,3,1,fpVideo);//写从SPS拷贝的前三个字节
unsigned char reserveBit0 = 0xFC;//111111
unsigned char lengthSizeMinusOne = m_nal.startcodesize - 1;
unsigned char d = reserveBit0 + lengthSizeMinusOne;
fwrite(&d,1,1,fpVideo);//NAL起始码字节数目
unsigned char numOfSequenceParameterSets = 0xE1;
fwrite(&numOfSequenceParameterSets,1,1,fpVideo);//SPS个数1个
unsigned char sequenceParameterSetLength[2];
unsigned int s = spsSize - m_nal.startcodesize;
sequenceParameterSetLength[1] = (unsigned char)(s&0xFF); s = s>>8;
sequenceParameterSetLength[0] = (unsigned char)(s&0xFF); s = s>>8;
fwrite(sequenceParameterSetLength,2,1,fpVideo);//写SPS长度
fwrite(sps+m_nal.startcodesize,spsSize-m_nal.startcodesize,1,fpVideo);//写SPS
free(sps);//释放内存
unsigned char numOfPictureParameterSets = 0x01; //PPS个数
fwrite(&numOfPictureParameterSets,1,1,fpVideo);//写PPS个数
unsigned char pictureParameterSetLength[2];
s = 8 - m_nal.startcodesize;
pictureParameterSetLength[1] = (unsigned char)(s&0xFF); s = s>>8;
pictureParameterSetLength[0] = (unsigned char)(s&0xFF); s = s>>8;
fwrite(pictureParameterSetLength,2,1,fpVideo);//写PPS长度
fwrite(m_nal.payload + m_nal.startcodesize,8-m_nal.startcodesize,1,fpVideo);//写PPS
fclose(fpVideo);
}
/* 封装 NAL*/
void encapsulateNAL()
{
/*FILE * fpVideos;
fpVideos = fopen("789.flv", "ab+");
fwrite(m_nal.payload,m_nal.size,1,fpVideos);
fclose(fpVideos);*/
FILE * fpVideo;
fpVideo = fopen("444.flv", "ab+"); //以只读二进制方式打开文件
setTagHeaderDataSize(m_nal.size - 41 + 5 + 4);//5为video头 4为NAL长度
writeTagHeader();
unsigned char data[5] = {0x17,0x01,0x00,0x00,0x00};//关键帧 H264 AVC sequence header Composition time offset = 00 00 00
fwrite(data,5,1,fpVideo);
unsigned char length[4];
unsigned int s = m_nal.size - 41;
length[3] = (unsigned char)(s&0xFF); s = s>>8;
length[2] = (unsigned char)(s&0xFF); s = s>>8;
length[1] = (unsigned char)(s&0xFF); s = s>>8;
length[0] = (unsigned char)(s&0xFF); s = s>>8;
//PrintBuffer(length, 4);
//sleep(10);
fwrite(length,4,1,fpVideo);//写NAL长度
unsigned char test[m_nal.size-41];
//memcpy(test,m_nal.payload+41,m_nal.size-41);
//PrintBuffer(test, m_nal.size-41);
/*FILE * fpVideoss;
fpVideoss = fopen("987.flv", "ab+");
fwrite(m_nal.payload+41,m_nal.size-41,1,fpVideoss);
fclose(fpVideoss);
sleep(10);*/
fwrite(m_nal.payload + 41, m_nal.size-41,1,fpVideo);//写NAL
fclose(fpVideo);
}
/* 封装 SEI*/
void encapsulateSEI()
{
FILE * fpVideo;
fpVideo = fopen("444.flv", "ab+"); //以只读二进制方式打开文件
unsigned char *sei = (unsigned char*)malloc(m_nal.size);
unsigned int seiSize = m_nal.size;
memcpy(sei,m_nal.payload,m_nal.size);
m_nal.nalType = (m_nal.payload[m_nal.startcodesize]&0x1F);//获取NAL类型
if(m_nal.nalType != NAL_SLICE_IDR)
{
printf("SEI after must be IDR\n");;
}
setTagHeaderDataSize(seiSize - m_nal.startcodesize + m_nal.size - m_nal.startcodesize + 8 + 5);//注意8是两个NAL的长度
writeTagHeader();
unsigned char data[5] = {0x17,0x01,0x00,0x00,0x00};//关键帧 H264 AVC sequence header Composition time offset = 00 00 00
fwrite(data,5,1,fpVideo);
unsigned char length[4];
unsigned int s = seiSize - m_nal.startcodesize;
length[3] = (unsigned char)(s&0xFF); s = s>>8;
length[2] = (unsigned char)(s&0xFF); s = s>>8;
length[1] = (unsigned char)(s&0xFF); s = s>>8;
length[0] = (unsigned char)(s&0xFF); s = s>>8;
fwrite(length,4,1,fpVideo);//写NAL长度
fwrite(sei + m_nal.startcodesize,seiSize-m_nal.startcodesize,1,fpVideo);//写NAL
free(sei);
s = m_nal.size - m_nal.startcodesize;
length[3] = (unsigned char)(s&0xFF); s = s>>8;
length[2] = (unsigned char)(s&0xFF); s = s>>8;
length[1] = (unsigned char)(s&0xFF); s = s>>8;
length[0] = (unsigned char)(s&0xFF); s = s>>8;
fwrite(length,4,1,fpVideo);//写NAL长度
fwrite(m_nal.payload + m_nal.startcodesize,m_nal.size-m_nal.startcodesize,1,fpVideo);//写NAL
fclose(fpVideo);
}
int flv_init( const char *filename, int fps,int width,int height)
{
setFlvHeader();
writeFirstTagSize();
writeMetaData();
//sleep(1);
return 0;
}
int flv_write_video_packet(unsigned char* packetData,int size,unsigned int ts)
{
//PrintBuffer(packetData, size);
//sleep(2);
cout << "原始长度: " << size << endl;
readNal(packetData, size);
//m_nal.nalType = (m_nal.payload[m_nal.startcodesize]&0x1F);//获取NAL类型
setTagHeader(TAGTYPE_VIDEO,ts);
//printf("Type: %02x\n", m_nal.payload[m_nal.startcodesize]);
//sleep(5);
//cout << "m_nal.startcodesize:" << m_nal.nalType << endl;
//cout << "Size:" << size << endl;
//cout << "NAL_SPS" << endl;
if(ts > 33){
encapsulateSPSPPS();
/* 写前一个Tag Size */
writePreTagSize();
encapsulateNAL();
/* 写前一个Tag Size */
writePreTagSize();
m_DTS += 1000.0/25;
}
return 0;
}
不知道你这个问题是否已经解决, 如果还没有解决的话: