fangtipin

fangtipin

0个粉丝

1

问答

0

专栏

0

资料

fangtipin  发布于  2024-10-12 11:21:07
采纳率 0%
1个问答
173

EB-RV1126-BC-191板子运行自己编码的程序

悬赏金¥ 10
问题最晚将于2024-10-19结题
   

需求是在 自己编码程序能在 EB-RV1126-BC-191板子内运行,能实现抓拍多种分辨率的图片和录制自定义时长的短视频保存到本地的功能。不知道开发思路,麻烦给介绍下。

我来回答
回答3个
时间排序
认可量排序

紫晓龙吟

11个粉丝

8

问答

0

专栏

0

资料

紫晓龙吟 2024-10-12 14:41:20
认可1

RKMedia 是对 RV1126/RV1109 内所有媒体资源调用进行了整合封装的一套 API 接口,它可以大大降低刚接触 RV1126/RV1109 芯片平台用户的开发成本,以少量代码就可以很快速、简单地调用 Soc 上所有媒体资源。同时 RKMedia 还提供了媒体资源以外的硬件资源联合调用 DEMO,如:RKAIQ、RKNN、RTSP 等等。RKMedia 的核心思想是把各个硬件资源独立成模块,模块开放出输入和输出端通过绑定的方式控制流从某个模块流出并且流入另外一个模块。

  1. 抓拍多种分辨率的图片,可以初始化相机最大分辨率,然后裁剪或者缩放等方式实现不同分辨率的图片,RGA可快速实现;
  2. 保存视频到本地,建议用VENC编码为h264,通过写文件方式保存到本地为MP4或者h264等文件,上位机通过vlc等软件可以观看;

ZacharyLi

0个粉丝

0

问答

0

专栏

1

资料

ZacharyLi 2024-10-12 15:36:54
认可1

使用EB-RV1126-BC-191板子则不需要考虑硬件驱动等问题。

可以参考以下两种方案:
一:封装ffmpeg命令,使用标准ffmpeg程序直接读取摄像头数据,编码保存都可以实现。
例如

ffmpeg -f video4linux2 -i "/dev/video0" -vcodec libx264 -pix_fmt yuv420p vidoData.h264

二:使用ffmpeg提供的api按需实现控制和数据流操作等。优点是使用灵活,可以集成到自动源码开发的界面程序中,比如QT程序。缺点是复杂度较高,纯c实现的example看起来比较复杂。
参考如下:

#include <string.h>

#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"

#define V_WIDTH 640
#define V_HEIGHT 480

//@brief
// return
static AVFormatContext *open_dev() {
    int ret = 0;
    char errors[1024] = {
        0,
    };

    // ctx
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;

    //摄像头的设备文件
    char *devicename = "/dev/video0";

    // register video device
    avdevice_register_all();

    // get format
    AVInputFormat *iformat = av_find_input_format("video4linux2");

    av_dict_set(&options, "video_size", "640x480", 0);
    av_dict_set(&options, "framerate", "30", 0);
    av_dict_set(&options, "pixel_format", "yuyv422", 0);

    // open device
    ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options);
    if (ret < 0) {
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open video device, [%d]%s\n", ret, errors);
        return NULL;
    }

    return fmt_ctx;
}

static void open_encoder(int width, int height, AVCodecContext **enc_ctx) {
    int ret = 0;
    AVCodec *codec = NULL;
    avcodec_register_all();

    codec = avcodec_find_encoder_by_name("libx264");
    if (!codec) {
        printf("Codec libx264 not found\n");
        exit(1);
    }

    *enc_ctx = avcodec_alloc_context3(codec);
    if (!enc_ctx) {
        printf("Could not allocate video codec context!\n");
        exit(1);
    }

    // SPS/PPS
    (*enc_ctx)->profile = FF_PROFILE_H264_HIGH_444;
    (*enc_ctx)->level = 50; //表示LEVEL是5.0

    //设置分辫率
    (*enc_ctx)->width = width;   // 640
    (*enc_ctx)->height = height; // 480

    // GOP
    (*enc_ctx)->gop_size = 250;
    (*enc_ctx)->keyint_min = 25; // option

    //设置B帧数据
    (*enc_ctx)->max_b_frames = 3; // option
    (*enc_ctx)->has_b_frames = 1; // option

    //参考帧的数量
    (*enc_ctx)->refs = 3; // option

    //设置输入YUV格式
    (*enc_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;

    //设置码率
    (*enc_ctx)->bit_rate = 600000; // 600kbps

    //设置帧率
    (*enc_ctx)->time_base = (AVRational){1, 30}; //帧与帧之间的间隔是time_base
    (*enc_ctx)->framerate = (AVRational){30, 1}; //帧率,每秒 30帧

    ret = avcodec_open2((*enc_ctx), codec, NULL);
    if (ret < 0) {
        printf("Could not open codec: %s!\n", av_err2str(ret));
        exit(1);
    }
}

static AVFrame *create_frame(int width, int height) {
    int ret = 0;
    AVFrame *frame = NULL;

    frame = av_frame_alloc();
    if (!frame) {
        printf("Error, No Memory!\n");
        goto __ERROR;
    }

    //设置参数
    frame->width = width;
    frame->height = height;
    frame->format = AV_PIX_FMT_YUV420P;

    // alloc inner memory
    ret = av_frame_get_buffer(frame, 32); //按 32 位对齐
    if (ret < 0) {
        printf("Error, Failed to alloc buffer for frame!\n");
        goto __ERROR;
    }

    return frame;

__ERROR:
    if (frame) {
        av_frame_free(&frame);
    }

    return NULL;
}

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *newpkt,
                   FILE *outfile) {
    int ret = 0;
    if (frame) {
        printf("send frame to encoder, pts=%lld", frame->pts);
    }
    //送原始数据给编码器进行编码
    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        printf("Error, Failed to send a frame for enconding!\n");
        exit(1);
    }

    //从编码器获取编码好的数据
    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, newpkt);

        //如果编码器数据不足时会返回  EAGAIN,或者到数据尾时会返回 AVERROR_EOF
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return;
        } else if (ret < 0) {
            printf("Error, Failed to encode!\n");
            exit(1);
        }

        fwrite(newpkt->data, 1, newpkt->size, outfile);
        fflush(outfile);
        av_packet_unref(newpkt);
    }
}

void yuyv422ToYuv420p(AVFrame *frame, AVPacket *pkt) {
    int i = 0;
    int yuv422_length = V_WIDTH * V_HEIGHT * 2;
    int y_index = 0;
    // copy all y
    for (i = 0; i < yuv422_length; i += 2) {
        frame->data[0][y_index] = pkt->data[i];
        y_index++;
    }

    // copy u and v
    int line_start = 0;
    int is_u = 1;
    int u_index = 0;
    int v_index = 0;
    // copy u, v per line. skip a line once
    for (i = 0; i < V_HEIGHT; i += 2) {
        // line i offset
        line_start = i * V_WIDTH * 2;
        for (int j = line_start + 1; j < line_start + V_WIDTH * 2; j += 4) {
            frame->data[1][u_index] = pkt->data[j];
            u_index++;
            frame->data[2][v_index] = pkt->data[j + 2];
            v_index++;
        }
    }
}

void rec_video() {
    int ret = 0;
    int base = 0;
    int count = 0;

    // pakcet
    AVPacket pkt;
    AVFormatContext *fmt_ctx = NULL;
    AVCodecContext *enc_ctx = NULL;

    // set log level
    av_log_set_level(AV_LOG_DEBUG);

    // create file
    char *yuvout = "./video.yuv";
    char *out = "./video.h264";

    FILE *yuvoutfile = fopen(yuvout, "wb+");
    FILE *outfile = fopen(out, "wb+");

    //打开设备
    fmt_ctx = open_dev();

    //打开编码器
    open_encoder(V_WIDTH, V_HEIGHT, &enc_ctx);

    //创建 AVFrame
    AVFrame *frame = create_frame(V_WIDTH, V_HEIGHT);

    //创建编码后输出的Packet
    AVPacket *newpkt = av_packet_alloc();
    if (!newpkt) {
        printf("Error, Failed to alloc avpacket!\n");
        goto __ERROR;
    }

    // read data from device
    while (((ret = av_read_frame(fmt_ctx, &pkt)) == 0) && (count++ < 100)) {
        int i = 0;
        av_log(NULL, AV_LOG_INFO, "packet size is %d(%p)\n", pkt.size,
               pkt.data);

        // YUYVYUYVYUYVYUYV   YUYV422
        // YYYYYYYYUUVV YUV420
        yuyv422ToYuv420p(frame, &pkt);

        fwrite(frame->data[0], 1, 307200, yuvoutfile);
        fwrite(frame->data[1], 1, 307200 / 4, yuvoutfile);
        fwrite(frame->data[2], 1, 307200 / 4, yuvoutfile);

        frame->pts = base++;
        encode(enc_ctx, frame, newpkt, outfile);
        //
        av_packet_unref(&pkt); // release pkt
    }

    encode(enc_ctx, NULL, newpkt, outfile);

__ERROR:
    if (yuvoutfile) {
        // close file
        fclose(yuvoutfile);
    }

    // close device and release ctx
    if (fmt_ctx) {
        avformat_close_input(&fmt_ctx);
    }

    av_log(NULL, AV_LOG_DEBUG, "finish!\n");
    return;
}

int main(int argc, char *argv[]) {
    rec_video();
    return 0;
}

37个粉丝

29

问答

32

专栏

59

资料

2024-10-14 08:59:59
认可0

第一种方法:参考rkmedia的实例,结合自己的需求进行修改,这个要求对rkmeida的那些接口有一定的熟悉。
第二种方法:打开ffmpeg选项,没有的话移植一个版本的ffmpeg,ffmpeg网上资料比较多。
第三种方法:移植opencv,这个也是网上资料比较多,但是这个由于又多封装了层,不像ffmpeg那样对一些硬件编解码做支持,所以使用方便的同时,可能会造成一些资源的损耗。

或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区