H264文件解析出nalu数据,送给ffmpeg解码,opencv显示
来源:互联网 发布:扫描条形码识别软件 编辑:程序博客网 时间:2024/05/08 15:35
本博客主要是H264的视频码流有ffmpeg 解码后,有opencv先,这里贴出全部代码,你只需自己建个工程,配置一下ffmpeg库和opencv3.0库就好了。(这里采用自己打开h264文件,解析出来每个nalu数据,把每一个nalu数据送给ffmpeg库,解码出yuv,然后把yuv转成BGR格式,用opencv显示出来)
头文件 H264.h
#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <string.h>#include <winsock2.h>typedef struct{ int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested) unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU) unsigned max_size; //! Nal Unit Buffer size int forbidden_bit; //! should be always FALSE int nal_reference_idc; //! NALU_PRIORITY_xxxx int nal_unit_type; //! NALU_TYPE_xxxx char *buf; //! contains the first byte followed by the EBSP unsigned short lost_packets; //! true, if packet loss is detected} NALU_t;int GetNalu();void FreeNALU(NALU_t *n);NALU_t *AllocNALU(int buffersize);void OpenBitstreamFile(char *fn);int GetAnnexbNALU(NALU_t *nalu);void dump(NALU_t *nal);int DumpChar(char * filename, char * buf, int len);FILE * getFile();
H264.cpp
// rtspSend.cpp : Defines the entry point for the console application.//#include <stdio.h>#include <stdlib.h>#include <string.h>#include <memory.h>#include "h264.h"static char* dumpRoot = ".\\dump\\";static char file2open[1024];#define UDP_MAX_SIZE 1400FILE *bits = NULL; //!< the bit stream filestatic int FindStartCode2(unsigned char *Buf);//查找开始字符0x000001static int FindStartCode3(unsigned char *Buf);//查找开始字符0x00000001// static int info2=0, info3=0;// RTP_FIXED_HEADER *rtp_hdr;// NALU_HEADER *nalu_hdr;// FU_INDICATOR *fu_ind;// FU_HEADER *fu_hdr;FILE * getFile(){ return bits;}//为NALU_t结构体分配内存空间NALU_t *AllocNALU(int buffersize){ NALU_t *nal =NULL; if ((nal = (NALU_t*)calloc (1, sizeof (NALU_t))) == NULL) { printf("AllocNALU: n"); exit(0); } nal->max_size=buffersize; if ((nal->buf = (char*)calloc (buffersize, sizeof (char))) == NULL) { free (nal); printf ("AllocNALU: nal->buf"); exit(0); } return nal;}//释放void FreeNALU(NALU_t *n){ if (n) { if (n->buf) { free(n->buf); n->buf=NULL; } free (n); }}void OpenBitstreamFile (char *fn){ if (NULL == (bits=fopen(fn, "rb"))) { printf("open file error\n"); exit(0); }}//这个函数输入为一个NAL结构体,主要功能为得到一个完整的NALU并保存在NALU_t的buf中,//获取他的长度,填充F,IDC,TYPE位。//并且返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度int GetAnnexbNALU (NALU_t *nalu){ int pos = 0; int StartCodeFound, rewind; unsigned char *Buf; if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL) printf ("GetAnnexbNALU: Could not allocate Buf memory\n"); nalu->startcodeprefix_len=3;//初始化码流序列的开始字符为3个字节 if (3 != fread (Buf, 1, 3, bits))//从码流中读3个字节 { free(Buf); return 0; } info2 = FindStartCode2 (Buf);//判断是否为0x000001 if(info2 != 1) { //如果不是,再读一个字节 if(1 != fread(Buf+3, 1, 1, bits))//读一个字节 { free(Buf); return 0; } info3 = FindStartCode3 (Buf);//判断是否为0x00000001 if (info3 != 1)//如果不是,返回-1 { free(Buf); return -1; } else { //如果是0x00000001,得到开始前缀为4个字节 pos = 4; nalu->startcodeprefix_len = 4; } } else { //如果是0x000001,得到开始前缀为3个字节 nalu->startcodeprefix_len = 3; pos = 3; } //查找下一个开始字符的标志位 StartCodeFound = 0; info2 = 0; info3 = 0; while (!StartCodeFound) { if (feof (bits))//判断是否到了文件尾 { nalu->len = (pos-1)-nalu->startcodeprefix_len; memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len); nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit free(Buf); return pos-1; } Buf[pos++] = fgetc (bits);//读一个字节到BUF中 info3 = FindStartCode3(&Buf[pos-4]);//判断是否为0x00000001 if(info3 != 1) info2 = FindStartCode2(&Buf[pos-3]);//判断是否为0x000001 StartCodeFound = (info2 == 1 || info3 == 1); } // Here, we have found another start code (and read length of startcode bytes more than we should // have. Hence, go back in the file rewind = (info3 == 1)? -4 : -3; if (0 != fseek (bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾 { free(Buf); printf("GetAnnexbNALU: Cannot fseek in the bit stream file"); } // Here the Start code, the complete NALU, and the next start code is in the Buf. // The size of Buf is pos, pos+rewind are the number of bytes excluding the next // start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code nalu->len = (pos+rewind)-nalu->startcodeprefix_len; memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//拷贝一个完整NALU,不拷贝起始前缀0x000001或0x00000001 nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit nalu->nal_reference_idc = nalu->buf[0] & 0x60; //2 bit nalu->nal_unit_type = (nalu->buf[0]) & 0x1f; //5 bit free(Buf); return (pos+rewind);//返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度}static int FindStartCode2 (unsigned char *Buf){ if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=1) return 0; //判断是否为0x000001,如果是返回1 else return 1;}static int FindStartCode3 (unsigned char *Buf){ if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=0 || Buf[3] !=1) return 0;//判断是否为0x00000001,如果是返回1 else return 1;}int rtpnum = 0;//输出NALU长度和TYPEvoid dump(NALU_t *nal){ if (!nal) return; printf("%3d, len: %6d ",rtpnum++, nal->len); printf("nal_unit_type: %x\n", nal->nal_unit_type);}int DumpChar(char * filename, char * buf, int len){ FILE* file; int w, h; unsigned char * temp = (unsigned char *)buf; sprintf(file2open, "%s%s", dumpRoot, filename); int mHeight = 0; int mWidth = 100; int mYu = 0; mHeight = len / 100; mYu = len % 100; file = fopen(file2open, "w+"); for (h = 0; h < mHeight; h++) { for (w = 0; w < mWidth - 1; w++) { fprintf_s(file, "%3x,", temp[h * mWidth + w]); } fprintf_s(file, "%3x\n", temp[h * mWidth + w]); } for (w = 0; w < mYu - 1; w++) { fprintf_s(file, "%3x,", temp[h * mWidth + w]); } fprintf_s(file, "%3x\n", temp[h * mWidth + w]); fclose(file); return 0;}
main.cpp
#include "H264.h"extern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#include "libavutil/avutil.h" };#include "opencv2/opencv.hpp"AVCodec *pCodec = NULL;AVCodecContext *pCodecCtx = NULL;SwsContext *img_convert_ctx = NULL;AVFrame *pFrame = NULL;AVFrame *pFrameBGR = NULL;int H264_Init(void){ /* register all the codecs */ avcodec_register_all(); /* find the h264 video decoder */ pCodec = avcodec_find_decoder(CODEC_ID_H264); if (!pCodec) { fprintf(stderr, "codec not found\n"); } pCodecCtx = avcodec_alloc_context3(pCodec); //初始化参数,下面的参数应该由具体的业务决定 //pCodecCtx->time_base.num = 1; //pCodecCtx->frame_number = 1; //每包一个视频帧 //pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; //pCodecCtx->bit_rate = 0; //pCodecCtx->time_base.den = 30;//帧率 //pCodecCtx->width = 960;//视频宽 //pCodecCtx->height = 544;//视频高 /* open the coderc */ if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { fprintf(stderr, "could not open codec\n"); } // Allocate video frame pFrame = avcodec_alloc_frame(); if (pFrame == NULL) return -1; // Allocate an AVFrame structure pFrameBGR = avcodec_alloc_frame(); if (pFrameBGR == NULL) return -1; return 0;}static int dumpCount = 0;static int first = 0;static uint8_t *out_buffer = NULL;int H264_2_RGB(char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize){ int decode_size; int numBytes; int av_result; uint8_t *buffer = NULL; printf("Video decoding\n"); int ret, got_picture; AVPacket packet; av_init_packet(&packet); packet.size = frame_size; packet.data = (uint8_t *)inputbuf; ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet); if (ret < 0) { printf("Decode Error. ret = %d(解码错误)\n", ret); return -1; } if (first == 0) { out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height)); avpicture_fill((AVPicture *)pFrameBGR, out_buffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); first = 1; } struct SwsContext *img_convert_ctx; img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameBGR->data, pFrameBGR->linesize); memcpy(outputbuf, pFrameBGR->data[0], pCodecCtx->width * pCodecCtx->height * 3); *outsize = pCodecCtx->width * pCodecCtx->height * 3; return 0;}void H264_Release(void){ avcodec_close(pCodecCtx); av_free(pCodecCtx); av_free(pFrame); av_free(pFrameBGR);}int main(int argc, char* argv[]) { OpenBitstreamFile("./x264.h264"); NALU_t *nal; char fName[300]; int Frame = 0; nal = AllocNALU(8000000);//为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针 H264_Init(); unsigned char *outputbuf = (unsigned char *)calloc(1000 * 1000, sizeof(char)); unsigned int outsize = 0; unsigned char *m_pData = (unsigned char *)calloc(1000 * 1000, sizeof(char)); int sizeHeBing = 0; while (!feof(getFile())) { GetAnnexbNALU(nal);//每执行一次,文件的指针指向本次找到的NALU的末尾, //下一个位置即为下个NALU的起始码0x000001 dump(nal);//输出NALU长度和TYPE sprintf(fName, "dump[Len=%d][%d].txt", nal->len, Frame); memset(m_pData, 0, 4); m_pData[3] = 1; memcpy(m_pData + 4, nal->buf, nal->len); sizeHeBing = nal->len + 4; Frame++; int ret = H264_2_RGB((char *)m_pData, sizeHeBing, outputbuf, &outsize); if(ret != 0) continue; cv::Mat image = cv::Mat(pCodecCtx->height, pCodecCtx->width, CV_8UC3); memcpy(image.data, outputbuf, pCodecCtx->height * pCodecCtx->width * 3); cv::imshow("xxx", image); cv::waitKey(40); //DumpChar(fName, nal->buf, nal->len); //Sleep(33); } FreeNALU(nal); return 0; }
阅读全文
0 0
- H264文件解析出nalu数据,送给ffmpeg解码,opencv显示
- ffmpeg解码h264文件,opencv显示
- ffmpeg 解码h264数据
- ffmpeg 解码h264数据
- ffmpeg 解码h264数据
- ffmpeg 解码h264数据
- ffmpeg 解码h264数据
- ffmpeg 解码h264数据
- ffmpeg解码h264文件
- ffmpeg解码+opencv显示
- D3D11显示ffmpeg解码出的YUV420P数据
- ffmpeg解码数据转为Mat通过opencv函数显示
- FFmpeg解码-Opencv数据显示-双线程调度
- FFMpeg视频解码+OpenCV显示
- FFmpeg + Opencv 解码和显示
- rtsp获取视频帧 ffmpeg解码h264数据 D3D显示yv12数据
- 从mp4,flv文件中解析出h264和aac,送解码器解码失败
- FFmpeg解码H264裸流并转换成opencv Mat
- Machine learning10------K-means聚类算法与EM算法的关系
- HandDraw(手绘)~demo
- Xilinx与Altera的FPGA区别
- LRCN(4) solver之train_test_lstm_RGB.prototxt
- 笔试Java实现单例设计模式(最优方案)
- H264文件解析出nalu数据,送给ffmpeg解码,opencv显示
- HDU 1429 胜利大逃亡(续)(BFS+状态压缩)
- 解决spring mvc静态资源无法访问的问题
- 最长上升子序列 (n^2&&nlogn)
- Network POJ
- hdu 6129 Just do it(找规律)
- MySQL的使用
- BaseDao的实现与使用
- 论文阅读-BoVW-pLSA