v4l2-ctl 查看摄像头支持的图像格式
bash
v4l2-ctl --list-formats-ext -d /dev/video60
从摄像头读取一张图片
main.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavutil/imgutils.h>
#include <libavutil/pixfmt.h>
#include <libavcodec/avcodec.h>
void capture_one_frame(const char* device, const char* output_file, int width, int height, const char* pix_fmt) {
AVFormatContext* fmt_ctx = NULL;
const AVInputFormat* input_fmt = NULL;
AVPacket pkt;
AVFrame* frame = NULL;
AVCodecParameters *codecpar = NULL;
const AVCodec *codec = NULL;
AVCodecContext *codec_ctx = NULL;
FILE* fp = NULL;
int ret;
// 注册所有设备和格式
avdevice_register_all();
// 查找 V4L2 输入格式
input_fmt = av_find_input_format("video4linux2");
if (!input_fmt) {
fprintf(stderr, "Cannot find input format\n");
return;
}
// 打开设备
ret = avformat_open_input(&fmt_ctx, device, input_fmt, NULL);
if (ret < 0) {
fprintf(stderr, "Cannot open input file\n");
return;
}
// 获取流信息
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Cannot find stream information\n");;
goto end;
}
// 打印流信息
printf("\n==== Stream Information ===\n\n");
av_dump_format(fmt_ctx, 0, device, 0);
printf("\n==== End of Stream Information ===\n");
// 分配帧
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Cannot allocate frame\n");
goto end;
}
// 获取编解码器参数
codecpar = fmt_ctx->streams[0]->codecpar;
codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
fprintf(stderr, "Cannot find codec\n");
goto end;
}
// 打印解码器名称
printf("Decoder: %s\n", avcodec_get_name(codecpar->codec_id));
// 分配编解码器上下文
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Cannot allocate codec context\n");
goto end;
}
// 将编解码器参数复制到编解码器上下文
avcodec_parameters_to_context(codec_ctx, codecpar);
// 打开编解码器
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Cannot open codec\n");
goto end;
}
// 读取一帧
ret = av_read_frame(fmt_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Cannot read frame\n");
goto end;
}
// 打印 AVPacket 的属性值
printf("AVPacket properties:\n");
printf(" Stream Index: %d\n", pkt.stream_index);
printf(" PTS: %" PRId64 "\n", pkt.pts);
printf(" DTS: %" PRId64 "\n", pkt.dts);
printf(" Duration: %" PRId64 "\n", pkt.duration);
printf(" Size: %d bytes\n", pkt.size);
printf(" Flags: %d\n", pkt.flags);
printf(" Data: %p\n", pkt.data);
// 解码帧
ret = avcodec_send_packet(codec_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Cannot send packet\n");
goto end;
}
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret < 0) {
fprintf(stderr, "Cannot receive frame\n");
goto end;
}
// 打印 AVFrame 的属性值
printf("AVFrame properties:\n");
printf(" PTS: %" PRId64 "\n", frame->pts);
printf(" DTS: %" PRId64 "\n", frame->pkt_dts);
printf(" Pict Type: %d\n", frame->pict_type);
printf(" Format: %s\n", av_get_pix_fmt_name(frame->format));
printf(" Width: %d\n", frame->width);
printf(" Height: %d\n", frame->height);
printf(" Linesize: %d\n", frame->linesize[0]);
printf(" Data: %p\n", frame->data[0]);
// 打开输出文件
fp = fopen(output_file, "wb");
if (!fp) {
fprintf(stderr, "Cannot open output file\n");
goto end;
}
// 写入帧数据
fwrite(frame->data[0], 1, av_image_get_buffer_size(av_get_pix_fmt(pix_fmt), width, height, 1), fp);
end:
// 清理
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
avcodec_free_context(&codec_ctx);
if (fp) {
fclose(fp);
}
}
int main(int argc, char* argv[]) {
const char* device = "/dev/video60";
const char* output_file = "output.yuv";
int width = 1280;
int height = 720;
const char* pix_fmt = "yuyv422";
capture_one_frame(device, output_file, width, height, pix_fmt);
return 0;
}
Makefile
Makefile
C_COMPILER = aarch64-rockchip1031-linux-gnu-gcc
CFLAGS = --sysroot=/home/lingke/mnt \
-I/home/lingke/mnt/usr/include/aarch64-linux-gnu
LDFLAGS = -B/home/lingke/mnt/usr/lib/aarch64-linux-gnu \
-Wl,-rpath-link,/home/lingke/mnt/usr/lib/aarch64-linux-gnu \
-lavcodec -lavformat -lavutil -lavfilter -lswscale -lswresample -lavdevice -lpostproc
main.exe: main.c
$(C_COMPILER) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean:
-rm -rf main.exe main.o
编译
go
make
拷贝到开发板
css
scp main.exe rk:~
在开发板上运行
bash
./main.exe
生成 output.yuv,拷贝到主机,用ffplay查看
ffplay 查看 output.yuv
css
ffplay -f rawvideo -pixel_format yuyv422 -video_size 1280x720 -i output.yuv