参考ffmpeg avc.c写的从文件中一帧帧读取h.264数据的demo
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <string.h>
-
- char* filebuf_;
- const char* pbuf_;
- int filesize_;
- unsigned char is_stop_;
-
-
- const char* AVCFindStartCodeInternal(const char *p, const char *end)
- {
- const char *a = p + 4 - ((ptrdiff_t)p & 3);
-
- for (end -= 3; p < a && p < end; p++) {
- if (p[0] == 0 && p[1] == 0 && p[2] == 1)
- return p;
- }
-
- for (end -= 3; p < end; p += 4) {
- unsigned int x = *(const unsigned int*)p;
- // if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
- // if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
- if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
- if (p[1] == 0) {
- if (p[0] == 0 && p[2] == 1)
- return p;
- if (p[2] == 0 && p[3] == 1)
- return p + 1;
- }
- if (p[3] == 0) {
- if (p[2] == 0 && p[4] == 1)
- return p + 2;
- if (p[4] == 0 && p[5] == 1)
- return p + 3;
- }
- }
- }
-
- for (end += 3; p < end; p++) {
- if (p[0] == 0 && p[1] == 0 && p[2] == 1)
- return p;
- }
-
- return end + 3;
- }
-
- const char* AVCFindStartCode(const char *p, const char *end)
- {
- const char *out = AVCFindStartCodeInternal(p, end);
- if (p<out && out<end && !out[-1]) out--;
- return out;
- }
-
-
- H264FrameReader_Init(const char* filename)
- {
- FILE* fp = fopen(filename, "rb");
- filebuf_ = 0;
- filesize_ = 0;
-
- if (fp)
- {
- int retval = 0;
- fseek(fp, 0, SEEK_END);
- filesize_ = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- filebuf_ = (char*)malloc(filesize_);
- retval = fread(filebuf_, 1, filesize_, fp);
-
- fclose(fp);
- }
- pbuf_ = filebuf_;
- }
-
- H264FrameReader_Free()
- {
- free(filebuf_);
- }
-
- H264FrameReader_ReadFrame(char* outBuf, int* outBufSize)
- {
- char* pbufout = 0;
- const char *p = 0;
- const char *end = 0;
- const char *nal_start, *nal_end;
-
-
- char startcodebuf[] = { 0x00, 0x00, 0x00, 0x01 };
- if (pbuf_ >= filebuf_ + filesize_)
- {
- return 0;
- }
-
- pbufout = outBuf;
- p = pbuf_;
- end = filebuf_ + filesize_;
-
- nal_start = AVCFindStartCode(p, end);
- while (nal_start < end)
- {
- unsigned int nal_size = 0;
- unsigned char nal_type = 0;
-
- while (!*(nal_start++));
-
- nal_end = AVCFindStartCode(nal_start, end);
-
- nal_size = nal_end - nal_start;
- nal_type = nal_start[0] & 0x1f;
-
- memcpy(pbufout, startcodebuf, 4);
- pbufout += 4;
- memcpy(pbufout, nal_start, nal_size);
- pbufout += nal_size;
-
- nal_start = nal_end;
- break;
- }
-
- *outBufSize = pbufout - outBuf;
- pbuf_ = nal_start;
-
- return 1;
- }
-
-
- int main(int argc, char **argv)
- {
- unsigned long max_size = 1280 * 720;
- int tmpbuf_len = 0;
- int current_read_len = 0;
- char* tmpbuf = (char*)malloc(max_size * 10);
-
- FILE *fp = fopen("out.h264", "wb+");
- if (!fp)
- {
- printf("open file error\n");
- return -1;
- }
-
-
- H264FrameReader_Init("test.h264");
- printf("file size = %d\n", filesize_);
- while (current_read_len < filesize_)
- {
- if (H264FrameReader_ReadFrame(tmpbuf, &tmpbuf_len))
- {
- printf("tmpbuf_len = %d\n", tmpbuf_len);
- fwrite(tmpbuf, tmpbuf_len, 1, fp);
- current_read_len += tmpbuf_len;
- }
- }
- fclose(fp);
- H264FrameReader_Free();
-
- return 0;
- }
从planar yuv420 文件中读取每一帧数据,从nvenc demo中参考来的,原理如下
1.通过fseek和ftell计算出文件的大小
2.通过yuv的分辨率可以计算出每一帧yuv数据的大小
3.通过上面两步可以计算出文件中包含多少帧的yuv数据,然后通过每一帧数据在文件中的偏移,就可以读出该帧数据
- int loadframe(uint8_t *yuvInput[3], FILE *hInputYUVFile, uint32_t frmIdx, uint32_t width, uint32_t height)
- {
- uint64_t fileOffset;
- uint32_t result;
- uint32_t dwInFrameSize = 0;
- int anFrameSize[3] = {};
-
- dwInFrameSize = width * height * 3 / 2;
- anFrameSize[0] = width * height;
- anFrameSize[1] = anFrameSize[2] = width * height / 4;
-
- //当前帧在文件中的偏移量:当前index * 每一帧的大小
- fileOffset = (uint64_t)dwInFrameSize * frmIdx;
- //seek到偏移处
- result = _fseeki64(hInputYUVFile, fileOffset, SEEK_SET);
- if (result == -1)
- {
- return -1;
- }
- //把当前帧的Y、U、V数据分别读取到对应的数组中
- fread(yuvInput[0], anFrameSize[0], 1, hInputYUVFile);
- fread(yuvInput[1], anFrameSize[1], 1, hInputYUVFile);
- fread(yuvInput[2], anFrameSize[2], 1, hInputYUVFile);
-
- return 0;
- }
-
- int main()
- {
-
- infp = fopen("yb.yuv", "rb");
- if (!infp)
- {
- printf("open in file failed\n");
- return -1;
- }
-
- uint8_t *yuv[3];
- int lumaPlaneSize, chromaPlaneSize;
-
- lumaPlaneSize = 1920 * 1080;
- chromaPlaneSize = lumaPlaneSize >> 2;
-
- yuv[0] = new uint8_t[lumaPlaneSize];
- yuv[1] = new uint8_t[chromaPlaneSize];
- yuv[2] = new uint8_t[chromaPlaneSize];
- memset(yuv[0], 0, lumaPlaneSize);
- memset(yuv[1], 0, chromaPlaneSize);
- memset(yuv[2], 0, chromaPlaneSize);
-
- uint64_t file_size = 0;
-
- _fseeki64(infp, 0, SEEK_END);
- file_size = _ftelli64(infp);
- _fseeki64(infp, 0, SEEK_SET);
- int totalFrames = file_size / (lumaPlaneSize + chromaPlaneSize + chromaPlaneSize);
-
- //遍历每一帧YUV数据
- for (int frm = 0; frm < totalFrames; frm++)
- {
- loadframe(yuv, infp, frm, 1920, 1080);
- //处理yuv数据
- //....
- }
-
- return 0;
- }