zoukankan      html  css  js  c++  java
  • 从文件中读取yuv和h264数据

    1.从文件中读取h264数据

    参考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
    ");
            return -1;
        }
    
    
        H264FrameReader_Init("test.h264");
        printf("file size = %d
    ", filesize_);
        while (current_read_len < filesize_)
        {
            if (H264FrameReader_ReadFrame(tmpbuf, &tmpbuf_len))
            {
                printf("tmpbuf_len = %d
    ", tmpbuf_len);
                fwrite(tmpbuf, tmpbuf_len, 1, fp);
                current_read_len += tmpbuf_len;
            }
        }
        fclose(fp);
        H264FrameReader_Free();
    
        return 0;
    }

    2.从文件中读取yuv数据

    从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
    ");
            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;
    }
  • 相关阅读:
    Google调试技巧总结
    Reorder List -- leetcode
    Java回合阵列List
    他们控制的定义(2.3):SurfaceView和SurfaceHolder
    ImageView建立selector在录音中遇到的小问题及解决方案
    cocos2d 简单的日常高仿酷跑游戏
    Xcode的小标记旁边的文件的名称的作用
    c++中的对象引用(object reference)与对象指针的区别
    UIColor深入研究(CGColor,CIColor)
    UIImage图片处理
  • 原文地址:https://www.cnblogs.com/CoderTian/p/7265126.html
Copyright © 2011-2022 走看看