c语言实现给yuv文件添加帧序号

来源:互联网 发布:任子行网络公 编辑:程序博客网 时间:2024/06/03 22:47

这是我14年刚工作时候写的代码。当时领导提出给yuv文件加帧序号,我就实现了这么一个算法。后来其实也没怎么用过,但是实现的思路挺有意思的。无意中给翻出来了,挂到网上来,更新一下我许久都没有更新的博客。。。。
先看图
这里写图片描述
这里写图片描述
main函数

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <string.h>#include "fun.h"int main(int argc, char *argv[]){    char InputVideoName[100];    char OutputVideoName[100];    int width;    int height;    int FrameNum;    enum VideoFormat format = YUV444;    enum NumColor color = BLACK;    enum NumPosition position = LeftBottom;    YuvVideoFrame yuv_video_frame;    time_t start_time, end_time;    FILE *ifp, *ofp;    int y_pixel_num, u_pixel_num, v_pixel_num;    struct NumColorInfo num_color_info;    struct LineInfo line_info;    int x, y; // 数字的位置坐标    if(argc != 9)    {        printf("Error!\n");        return -1;    }    strcpy(InputVideoName, argv[1]);    strcpy(OutputVideoName, argv[2]);    width = atoi(argv[3]);    height = atoi(argv[4]);    FrameNum = atoi(argv[5]); // 帧数    format = (enum VideoFormat)atoi(argv[6]); // 格式 0表示yuv444,1表示yuv420 planar, 2表示yuv422 planar    color = (enum NumColor)atoi(argv[7]); // 字体颜色 0表示黑色,1表示白色,2表示红色,3表示绿色,4表示蓝色    position = (enum NumPosition)atoi(argv[8]); // 帧序号的位置 0表示左上角,1表示右上角,2表示左下角,3表示右下角    start_time = time(NULL);    // 初始化帧    yuv_video_frame = (YuvVideoFrame)malloc(sizeof(struct YuvFrame));    if(NULL == yuv_video_frame)    {        printf("run out of memory\n");        exit(0);    }    InitializeFrame(width, height, format, yuv_video_frame);    // 初始化颜色信息    InitializeNumColorInfo(color, num_color_info);    // 初始化数字线条和起始位置信息    InitializeLineAndPositionInfo(width, height, position, line_info, x, y);    // 打开输入输出文件    if((ifp = fopen(InputVideoName, "rb")) == NULL)    {        printf("cannot open %s\n", InputVideoName);        return -1;    }    if((ofp = fopen(OutputVideoName, "ab")) == NULL)    {        printf("cannot open %s\n", OutputVideoName);        return -1;    }    y_pixel_num = width * height;    switch(yuv_video_frame->format)    {        case YUV444:             u_pixel_num = y_pixel_num;            v_pixel_num = y_pixel_num;            break;        case YUV420:            u_pixel_num = y_pixel_num / 4;            v_pixel_num = y_pixel_num / 4;            break;        case YUV422:            u_pixel_num = y_pixel_num / 2;            v_pixel_num = y_pixel_num / 2;            break;        default:            break;    }    for(int frame_num = 0; frame_num < FrameNum; frame_num++)    {        fread(yuv_video_frame->y_component, sizeof(uchar), y_pixel_num, ifp);        fread(yuv_video_frame->u_component, sizeof(uchar), u_pixel_num, ifp);        fread(yuv_video_frame->v_component, sizeof(uchar), v_pixel_num, ifp);        AddNumInYuvVideo(frame_num, x, y, line_info, num_color_info, yuv_video_frame);        fwrite(yuv_video_frame->y_component, sizeof(uchar), y_pixel_num, ofp);        fwrite(yuv_video_frame->u_component, sizeof(uchar), u_pixel_num, ofp);        fwrite(yuv_video_frame->v_component, sizeof(uchar), v_pixel_num, ofp);    }    fclose(ifp);    fclose(ofp);    DisposeFrame(yuv_video_frame);    end_time = time(NULL);    //printf("\ntime = %d\n", end_time - start_time);    return 0;}

头文件 fun.h

enum VideoFormat{YUV444, YUV420, YUV422};  // 视频格式enum NumColor{BLACK, WHITE, RED, GREEN, BLUE}; // 数字颜色enum NumPosition{LeftTop, RightTop, LeftBottom, RightBottom}; // 数字的位置typedef unsigned char uchar;typedef struct YuvFrame *YuvVideoFrame;#define MAX(a, b)  ((a) > (b) ? (a) : (b))// YUV视频帧struct YuvFrame{    int width; // 视频帧宽    int height; // 视频帧高    enum VideoFormat format; // 视频的格式    uchar *y_component; // y分量    uchar *u_component; // u分量    uchar *v_component; // v分量};// 数字颜色信息struct NumColorInfo{    uchar y_value;    uchar u_value;    uchar v_value;};// 数字线条信息struct LineInfo{    int length; // 线条长    int width; // 线条宽};// 将字符串转换为数字int atoi(char *s);/****************************************************************************InitializeFrame:    初始化视频帧input:    int width 视频帧的宽    int height 视频帧的高    enum VideoFormat format 视频的格式output:    YuvVideoFrame yuv_video_framereturn:****************************************************************************/void InitializeFrame(int width, int height, enum VideoFormat format, YuvVideoFrame yuv_video_frame);/****************************************************************************DisposeFrame:    释放视频帧input:    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void DisposeFrame(YuvVideoFrame yuv_video_frame);/****************************************************************************AddLine:    在YUV视频帧上添加线条input:    int x 位置坐标    int y     int width 添加线条的宽    int height 添加线条的高     struct NumColorInfo num_color_info  数字的颜色    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddLine(int x, int y,              int width, int height,              struct NumColorInfo num_color_info,             YuvVideoFrame yuv_video_frame);/****************************************************************************AddDigit:    在YUV视频上添加数字input:    int digit 添加数字    int x 位置坐标    int y     struct LineInfo info_line 数字线条信息    struct NumColorInfo num_color_info 数字颜色    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddDigit(int digit,              int x, int y,               struct LineInfo info_line,              struct NumColorInfo num_color_info,              YuvVideoFrame yuv_video_frame);/****************************************************************************AddNumInYuvVideo:    在YUV视频上添加帧序号input:    int frame_num  帧序号    int x 数字起始位置坐标    int y      struct LineInfo line_info  数字线条信息    struct NumColorInfo num_color_info  颜色信息    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddNumInYuvVideo(int frame_num, int x, int y, struct LineInfo line_info, struct NumColorInfo num_color_info, YuvVideoFrame yuv_video_frame);/****************************************************************************InitializeNumColorInfo:    初始化数字的颜色信息input:    enum NumColor coloroutput:    struct NumColorInfo &num_color_inforeturn:****************************************************************************/void InitializeNumColorInfo(enum NumColor color, struct NumColorInfo &num_color_info);/****************************************************************************InitializeLineAndPositionInfo:    初始化线条和位置信息input:    int width  视频帧宽    int height  视频帧高    enum NumPosition positionoutput:    struct LineInfo &line_info 线条信息    int &x 数字起始坐标    int &yreturn:****************************************************************************/void InitializeLineAndPositionInfo(int width, int height, enum NumPosition position, struct LineInfo &line_info, int &x, int &y);

调用的函数,文件fun.cpp

#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include "fun.h"// 将字符串转换为数字int atoi(char *s){    int sign;    int n;    while(*s == ' ')        s++;    sign = (*s == '-') ? -1 : 1;    if('-' == *s || '+' == *s)        s++;    for(n = 0; isdigit(*s); s++)    {        n = n * 10 + (*s - '0');    }    return n * sign;}/****************************************************************************InitializeFrame:    初始化视频帧input:    int width 视频帧的宽    int height 视频帧的高    enum VideoFormat format 视频的格式output:    YuvVideoFrame yuv_video_framereturn:****************************************************************************/void InitializeFrame(int width, int height, enum VideoFormat format, YuvVideoFrame yuv_video_frame){    int y_pixel_num, u_pixel_num, v_pixel_num;    yuv_video_frame->width = width;    yuv_video_frame->height = height;    yuv_video_frame->format = format;    y_pixel_num = width * height;    switch(format)    {    case YUV444:        u_pixel_num = width * height;        v_pixel_num = width * height;        break;    case YUV420:        u_pixel_num = width * height / 4;        v_pixel_num = width * height / 4;        break;    case YUV422:        u_pixel_num = width * height / 2;        v_pixel_num = width * height / 2;        break;    default:        break;    }    yuv_video_frame->y_component = (uchar *)malloc(y_pixel_num * sizeof(uchar));    if(NULL == yuv_video_frame->y_component)    {        printf("run out of memory\n");        exit(0);    }    yuv_video_frame->u_component = (uchar *)malloc(u_pixel_num * sizeof(uchar));    if(NULL == yuv_video_frame->u_component)    {        printf("run out of memory\n");        exit(0);    }    yuv_video_frame->v_component = (uchar *)malloc(v_pixel_num * sizeof(uchar));    if(NULL == yuv_video_frame->v_component)    {        printf("run out of memory\n");        exit(0);    }}/****************************************************************************DisposeFrame:    释放视频帧input:    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void DisposeFrame(YuvVideoFrame yuv_video_frame){    free(yuv_video_frame->y_component);    free(yuv_video_frame->u_component);    free(yuv_video_frame->v_component);    free(yuv_video_frame);}/****************************************************************************AddLine:    在YUV视频帧上添加线条input:    int x 位置坐标    int y     int width 添加线条的宽    int height 添加线条的高     struct NumColorInfo num_color_info  数字的颜色    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddLine(int x, int y,              int width, int height,              struct NumColorInfo num_color_info,             YuvVideoFrame yuv_video_frame){    int i, j;    if(YUV444 == yuv_video_frame->format)    {        for(i = 0; i < height; i++)        {            for(j = 0; j < width; j++)            {                *(yuv_video_frame->y_component + (y + i) * yuv_video_frame->width + (x + j)) = num_color_info.y_value;                *(yuv_video_frame->u_component + (y + i) * yuv_video_frame->width + (x + j)) = num_color_info.u_value;                *(yuv_video_frame->v_component + (y + i) * yuv_video_frame->width + (x + j)) = num_color_info.v_value;            }        }    }    if(YUV420 == yuv_video_frame->format)    {        for(i = 0; i < height; i++)        {            for(j = 0; j < width; j++)            {                *(yuv_video_frame->y_component + (y + i) * yuv_video_frame->width + (x + j)) = num_color_info.y_value;                *(yuv_video_frame->u_component + (y + i) / 2 * yuv_video_frame->width / 2 + (x + j) / 2) = num_color_info.u_value;                *(yuv_video_frame->v_component + (y + i) / 2 * yuv_video_frame->width / 2 + (x + j) / 2) = num_color_info.v_value;            }        }    }    if(YUV422 == yuv_video_frame->format)    {        for(i = 0; i < height; i++)        {            for(j = 0; j < width; j++)            {                *(yuv_video_frame->y_component + (y + i) * yuv_video_frame->width + (x + j)) = num_color_info.y_value;                *(yuv_video_frame->u_component + (y + i) * yuv_video_frame->width / 2 + (x + j) / 2) = num_color_info.u_value;                *(yuv_video_frame->v_component + (y + i) * yuv_video_frame->width / 2 + (x + j) / 2) = num_color_info.v_value;            }        }    }}/****************************************************************************AddDigit:    在YUV视频上添加数字input:    int digit 添加数字    int x 位置坐标    int y     struct LineInfo info_line 数字线条信息    struct NumColorInfo num_color_info 数字颜色    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddDigit(int digit,              int x, int y,               struct LineInfo info_line,              struct NumColorInfo num_color_info,              YuvVideoFrame yuv_video_frame){    int line_width = info_line.width;    int line_length = info_line.length;    if(0 == digit || 4 == digit || 5 == digit || 6 == digit || 8 == digit || 9 == digit)    {        AddLine(x, y + line_width, line_width, line_length, num_color_info, yuv_video_frame);    }    if(0 == digit || 2 == digit || 6 == digit || 8 == digit)    {        AddLine(x, y + line_width * 2 + line_length, line_width, line_length, num_color_info, yuv_video_frame);    }    if(0 == digit || 1 == digit || 2 == digit || 3 == digit || 4 == digit || 7 == digit || 8 == digit || 9 == digit)    {        AddLine(x + line_width + line_length, y + line_width, line_width, line_length, num_color_info, yuv_video_frame);    }    if(0 == digit || 1 == digit || 3 == digit || 4 == digit || 5 == digit || 6 == digit || 7 == digit || 8 == digit || 9 == digit)    {        AddLine(x + line_width + line_length, y + line_width * 2 + line_length, line_width, line_length, num_color_info, yuv_video_frame);    }    if(0 == digit || 2 == digit || 3 == digit || 5 == digit || 6 == digit || 7 == digit || 8 == digit || 9 == digit)    {        AddLine(x + line_width, y, line_length, line_width, num_color_info, yuv_video_frame);    }    if(2 == digit || 3 == digit || 4 == digit || 5 == digit || 6 == digit || 8 == digit || 9 == digit)    {        AddLine(x + line_width, y + line_width + line_length, line_length, line_width, num_color_info, yuv_video_frame);    }    if(0 == digit || 2 == digit || 3 == digit || 5 == digit || 6 == digit || 8 == digit)    {        AddLine(x + line_width, y + line_width * 2 + line_length * 2, line_length, line_width, num_color_info, yuv_video_frame);    }}/****************************************************************************AddNumInYuvVideo:    在YUV视频上添加帧序号input:    int frame_num  帧序号    int x 数字起始位置坐标    int y      struct LineInfo line_info  数字线条信息    struct NumColorInfo num_color_info  颜色信息    YuvVideoFrame yuv_video_frameoutput:return:****************************************************************************/void AddNumInYuvVideo(int frame_num, int x, int y, struct LineInfo line_info, struct NumColorInfo num_color_info, YuvVideoFrame yuv_video_frame){    int distance;    int i;    int digit;    distance = line_info.width * 6 + line_info.length;    i = 0;    do{        digit = frame_num % 10;        AddDigit(digit, x - i * distance, y, line_info, num_color_info, yuv_video_frame);        i++;    }while(frame_num /= 10);}/****************************************************************************InitializeNumColorInfo:    初始化数字的颜色信息input:    enum NumColor coloroutput:    struct NumColorInfo &num_color_inforeturn:****************************************************************************/void InitializeNumColorInfo(enum NumColor color, struct NumColorInfo &num_color_info){    switch(color)    {    case BLACK: // 黑色        num_color_info.y_value = 16;        num_color_info.u_value = 128;        num_color_info.v_value = 128;        break;    case WHITE: // 白色        num_color_info.y_value = 235;        num_color_info.u_value = 128;        num_color_info.v_value = 128;        break;    case RED:  // 红色        num_color_info.y_value = 65;        num_color_info.u_value = 100;        num_color_info.v_value = 212;        break;    case GREEN: // 绿色        num_color_info.y_value = 112;        num_color_info.u_value = 72;        num_color_info.v_value = 58;        break;    case BLUE: // 蓝色        num_color_info.y_value = 35;        num_color_info.u_value = 212;        num_color_info.v_value = 114;        break;    default:  // 其他情况黑色        num_color_info.y_value = 16;        num_color_info.u_value = 128;        num_color_info.v_value = 128;        break;    }}/****************************************************************************InitializeLineAndPositionInfo:    初始化线条和位置信息input:    int width  视频帧宽    int height  视频帧高    enum NumPosition positionoutput:    struct LineInfo &line_info 线条信息    int &x 数字起始坐标    int &yreturn:****************************************************************************/void InitializeLineAndPositionInfo(int width, int height, enum NumPosition position, struct LineInfo &line_info, int &x, int &y){    line_info.length = width / 100;  // 线条的长度    line_info.width = MAX(width / 400, 1);  // 线条的宽度    // 数字的起始位置    switch(position)    {    case LeftTop: // 左上角        x = line_info.width * 22 + line_info.length * 3;        y = line_info.width * 4;        break;    case RightTop: // 右上角        x = width - line_info.width * 6 - line_info.length;        y = line_info.width * 4;        break;    case LeftBottom: // 左下角        x = line_info.width * 22 + line_info.length * 3;        y = height - line_info.width * 7 - line_info.length * 2;        break;    case RightBottom: // 右下角        x = width - line_info.width * 6 - line_info.length;        y = height - line_info.width * 7 - line_info.length * 2;        break;    default:        break;    }}
0 0