H.264——从码流中提取NAL Unit的有效数据

分析

视频编解码——H.264码流封装格式:流格式与包格式

在这里插入图片描述
打开一个H.264文件,可以看到h.264的起始码是0x00 00 00 01或0x00 00 01。

001和0001的区别

当一张图片分成多个slice发送

  • 0001——当一帧视频被分为多个slice时,起始的slice是0001
  • 001——起始slice后的slice是001

到下一个p帧的slice是0001

错误想法

用fgetc直接读文件,foef来循环。

思考一下为什么有的公司使用性能强大的芯片做出的产品反而没有使用普通芯片做出的产品优秀。
再思考一下对文件进行操作和对内存进行操作的效率不同。
再思考对文件进行操作的弊端。

正确做法应是对内存进行操作

测试代码

.c

#include "LUX_TEST_Get264.h"

typedef unsigned char uint8;
LUX_OSD_DataPoint dataPoint;
LUX_OSD_FilePoint filePoint;
int offset = 0;

/**
 * @description: 初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_Init(void)
{
    int ret = LUX_SUCCESS;
    int len = 0;

    do
    {
        /*打开264文件*/
        filePoint.h264File = fopen(LUX_TEST_File, "r");
        if (NULL == filePoint.h264File)
        {
            printf("fopen h264file failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }

        /*malloc*/
        dataPoint.h264Data = malloc(LUX_TEST_FileSpace);
        if (NULL == dataPoint.h264Data)
        {
            printf("malloc dataPoint.h264Data failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }

        /*h264实际数据*/
        dataPoint.dstData = malloc(128);
        if (NULL == dataPoint.dstData)
        {
            printf("malloc dataPoint.dstData failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }

        /*存放h264实际数据*/
        filePoint.saveH264 = fopen(LUX_TEST_DestFile,"w+"); 
        if(NULL == filePoint.saveH264)
        {
            printf("fopen LUX_FONT_WRITE_FILE failed\n");
        }

        /*读入内存*/
        len = fread(dataPoint.h264Data, 1, LUX_TEST_FileSpace, filePoint.h264File);
        if (0 == len)
        {
            printf("fread dataPoint.h264Data failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }
    }while(0);

    return ret;
}

/**
 * @description: 抓取h264数据并存储
 * @param [in] void
 * @return 
 */
int LUX_TEST_Func(void)
{
    int ret = LUX_SUCCESS;
    int getDataOffset = 0;
    int len = 0;

    do{

        while(1)
        {
            if (*(dataPoint.h264Data + offset) == 0 && *(dataPoint.h264Data + offset + 1) == 0)
            {
                if (*(dataPoint.h264Data + offset + 2) == 1)
                {
                    /*0x 00 00 01*/
                    printf("++++++++++\n");

                    break;
                }

                else if (*(dataPoint.h264Data + offset + 2) == 0 && *(dataPoint.h264Data + offset + 3) == 1)
                {
                    /*0x 00 00 00 01*/
                    printf("==========\n");

                    do
                    {
                        getDataOffset++;
                        *(dataPoint.dstData + getDataOffset) = *(dataPoint.h264Data + offset + 3 + getDataOffset);

                        if (*(dataPoint.h264Data + 3 + getDataOffset + 1) == 0 && *(dataPoint.h264Data + 3 + getDataOffset + 2) == 0 && 
                        *(dataPoint.h264Data + 3 + getDataOffset + 3) == 0 && *(dataPoint.h264Data + 3 + getDataOffset + 4) == 1)
                        {
                            len = fwrite(dataPoint.dstData, 1, LUX_TEST_FileSpace, filePoint.saveH264);
                            if (len <= 0)
                            {
                                printf("fwrite dataPoint.h264Data failed\n");
                                perror("why");
                                return LUX_FAILED;
                            }
                            break;
                        }
                    } while (1);

                    break;
                }
            }

            offset++;
        }

    }while(0);

    return ret;
}

/**
 * @description: 去初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_DeInit(void)
{
    free(dataPoint.h264Data);
    free(dataPoint.dstData);

    fclose(filePoint.h264File);
}

int main()
{
    int ret = LUX_FAILED;
    
    ret = LUX_TEST_Init();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_Init error\n");
        return LUX_FAILED;
    }

    ret = LUX_TEST_Func();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_Func error\n");
        return LUX_FAILED;
    }

    ret = LUX_TEST_DeInit();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_DeInit error\n");
        return LUX_FAILED;
    }

    return LUX_SUCCESS;
}

.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>

#define LUX_TEST_File       "test.264"
#define LUX_TEST_DestFile   "destFile"

#define LUX_TEST_FileSpace  0x2040
#define LUX_SUCCESS         0
#define LUX_FAILED          -1

typedef struct
{
    char *h264Data;      //YUV
    char *dstData;      //dst data
}LUX_OSD_DataPoint;

typedef struct
{
    FILE *h264File;     //打开264
    FILE *saveH264;     //存h264实际数据
}LUX_OSD_FilePoint;


/**
 * @description: 初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_Init(void);

/**
 * @description: 抓取h264数据并存储
 * @param [in] void
 * @return 
 */
int LUX_TEST_Func(void);

/**
 * @description: 去初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_DeInit(void);

效果

在这里插入图片描述
能抓出第一个nalu的数据。
由于我们不知道抓出来的nalu数据有多长,所以空间开的比较大,后面全部是0。这里也不知道后面的三个0是由于内存无数据置0还是没有舍弃掉第二个nalu起始码的0。所以我们需要优化代码。

代码优化分析

一个一个字节往文件里写

.c

#include "LUX_TEST_Get264.h"

typedef unsigned char uint8;
LUX_OSD_DataPoint dataPoint;
LUX_OSD_FilePoint filePoint;
int offset = 0;

/**
 * @description: 初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_Init(void)
{
    int ret = LUX_SUCCESS;
    int len = 0;

    do
    {
        /*打开264文件*/
        filePoint.h264File = fopen(LUX_TEST_File, "r");
        if (NULL == filePoint.h264File)
        {
            printf("fopen h264file failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }

        /*malloc*/
        dataPoint.h264Data = malloc(LUX_TEST_FileSpace);
        if (NULL == dataPoint.h264Data)
        {
            printf("malloc dataPoint.h264Data failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }

        /*存放h264实际数据*/
        filePoint.saveH264 = fopen(LUX_TEST_DestFile,"w+"); 
        if(NULL == filePoint.saveH264)
        {
            printf("fopen LUX_FONT_WRITE_FILE failed\n");
        }

        /*读入内存*/
        len = fread(dataPoint.h264Data, 1, LUX_TEST_FileSpace, filePoint.h264File);
        if (0 == len)
        {
            printf("fread dataPoint.h264Data failed\n");
            perror("why");
            ret = LUX_FAILED;
            break;
        }
    }while(0);

    return ret;
}

/**
 * @description: 抓取h264数据并存储
 * @param [in] void
 * @return 
 */
int LUX_TEST_Func(void)
{
    int ret = LUX_SUCCESS;
    int getDataOffset = 0;
    int len = 0;

    do{

        while(1)
        {
            if (*(dataPoint.h264Data + offset) == 0 && *(dataPoint.h264Data + offset + 1) == 0)
            {
                if (*(dataPoint.h264Data + offset + 2) == 1)
                {
                    /*0x 00 00 01*/
                    //TODO:和下面一样
                    break;
                }

                else if (*(dataPoint.h264Data + offset + 2) == 0 && *(dataPoint.h264Data + offset + 3) == 1)
                {
                    /*0x 00 00 00 01*/
                    do
                    {
                        getDataOffset++;

                        len = fwrite(dataPoint.h264Data + offset + 3 + getDataOffset, 1, 1, filePoint.saveH264);
                        if (len <= 0)
                        {
                            printf("fwrite dataPoint.h264Data failed\n");
                            perror("why");
                            return LUX_FAILED;
                        }

                        if (*(dataPoint.h264Data + 3 + getDataOffset + 1) == 0 && *(dataPoint.h264Data + 3 + getDataOffset + 2) == 0 && 
                        *(dataPoint.h264Data + 3 + getDataOffset + 3) == 0 && *(dataPoint.h264Data + 3 + getDataOffset + 4) == 1)
                            break;
                    } while (1);

                    break;
                }
            }

            offset++;
        }

    }while(0);

    return ret;
}

/**
 * @description: 去初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_DeInit(void)
{
    free(dataPoint.h264Data);

    fclose(filePoint.h264File);
}

int main()
{
    int ret = LUX_FAILED;
    
    ret = LUX_TEST_Init();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_Init error\n");
        return LUX_FAILED;
    }

    ret = LUX_TEST_Func();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_Func error\n");
        return LUX_FAILED;
    }

    ret = LUX_TEST_DeInit();
    if(LUX_FAILED == ret)
    {
        printf("LUX_TEST_DeInit error\n");
        return LUX_FAILED;
    }

    return LUX_SUCCESS;
}

.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>

#define LUX_TEST_File       "test.264"
#define LUX_TEST_DestFile   "destFile"

#define LUX_TEST_FileSpace  0x2040
#define LUX_SUCCESS         0
#define LUX_FAILED          -1

typedef struct
{
    char *h264Data;      //YUV
}LUX_OSD_DataPoint;

typedef struct
{
    FILE *h264File;     //打开264
    FILE *saveH264;     //存h264实际数据
}LUX_OSD_FilePoint;


/**
 * @description: 初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_Init(void);

/**
 * @description: 抓取h264数据并存储
 * @param [in] void
 * @return 
 */
int LUX_TEST_Func(void);

/**
 * @description: 去初始化
 * @param [in] void
 * @return 
 */
int LUX_TEST_DeInit(void);

最终效果

在这里插入图片描述
拿到想要的数据

思考:要拿出第二个该怎么做

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spark!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值