FFmpeg实现获取USB摄像头视频流测试代码

矫情吗;* 2022-10-03 00:33 1045阅读 0赞

通过USB摄像头(注:windows7/10下使用内置摄像头,linux下接普通的usb摄像头(Logitech))获取视频流用到的模块包括avformat和avdevice。头文件仅include avdevice.h即可,因为avdevice.h中会include avformat.h。libavdevice库是libavformat的一个补充库(complementary library)。主要涉及到的接口函数包括:

  1. avdevice_register_all:初始化libavdevice库并注册所有输入输出设备;

  2. av_find_input_format:根据输入格式的名字查找AVInputFormat,在测试代码中,windows平台使用”vfwcap”(video for windows capture),linux平台使用”v4l2”(Video4Linux2);

  3. avformat_alloc_context:分配AVFormatContext;

  4. avformat_open_input:打开输入流并读取header;

  5. avformat_find_stream_info:读取媒体文件的数据包以获取流信息;

  6. 通过AVFormatContext中AVStream查找视频/音频流索引,这里在windows10下获取到的编码类型为mjpeg即AV_CODEC_ID_MJPEG,像素格式为yuv422p即AV_PIX_FMT_YUVJ422P;在linux或windows7下获取到的编码类型为rawvideo即AV_CODEC_ID_RAWVIDEO,像素格式yuyv422即AV_PIX_FMT_YUYV422;可见摄像头类型不同、系统不同获取到的编码类型和像素格式可能也不同;

  7. av_read_frame:获取流即packet(AVPacket);

  8. av_packet_unref:释放packet引用的缓冲区;

  9. avformat_close_input:关闭打开的输入AVFormatContext。

测试代码如下(test_ffmpeg_usb_stream.cpp):

  1. #include "funset.hpp"
  2. #include <iostream>
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. #include <libavdevice/avdevice.h>
  7. #ifdef __cplusplus
  8. }
  9. #endif
  10. int test_ffmpeg_usb_stream()
  11. {
  12. avdevice_register_all();
  13. #ifdef _MSC_VER
  14. const char* input_format_name = "vfwcap";
  15. const char* url = "";
  16. #else
  17. const char* input_format_name = "v4l2";
  18. const char* url = "/dev/video0";
  19. #endif
  20. AVInputFormat* fmt = av_find_input_format(input_format_name);
  21. AVFormatContext* ctx = avformat_alloc_context();
  22. int ret = avformat_open_input(&ctx, url, fmt, nullptr);
  23. if (ret != 0) {
  24. fprintf(stderr, "fail to open input stream: %d\n", ret);
  25. return -1;
  26. }
  27. // read packets of a media file to get stream information
  28. ret = avformat_find_stream_info(ctx, nullptr);
  29. if (ret < 0) {
  30. fprintf(stderr, "fail to get stream information: %d\n", ret);
  31. return -1;
  32. }
  33. // find audio/video stream index
  34. int video_stream_index = -1;
  35. int audio_stream_index = -1;
  36. fprintf(stdout, "Number of elements in AVFormatContext.streams: %d\n", ctx->nb_streams);
  37. for (int i = 0; i < ctx->nb_streams; ++i) {
  38. const AVStream* stream = ctx->streams[i];
  39. fprintf(stdout, "type of the encoded data: %d\n", stream->codecpar->codec_id);
  40. if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  41. video_stream_index = i;
  42. fprintf(stdout, "dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n",
  43. stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
  44. }
  45. else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  46. audio_stream_index = i;
  47. fprintf(stdout, "audio sample format: %d\n", stream->codecpar->format);
  48. }
  49. }
  50. if (video_stream_index == -1) {
  51. fprintf(stderr, "Error: no video stream\n");
  52. return -1;
  53. }
  54. if (audio_stream_index == -1) {
  55. fprintf(stdout, "Warning: no audio stream\n");
  56. }
  57. int cnt = 0;
  58. AVPacket pkt;
  59. while (1) {
  60. if (++cnt > 100) break;
  61. ret = av_read_frame(ctx, &pkt);
  62. if (ret < 0) {
  63. fprintf(stderr, "error or end of file: %d\n", ret);
  64. continue;
  65. }
  66. if (pkt.stream_index == video_stream_index) {
  67. fprintf(stdout, "video stream, packet size: %d\n", pkt.size);
  68. }
  69. if (pkt.stream_index == audio_stream_index) {
  70. fprintf(stdout, "audio stream, packet size: %d\n", pkt.size);
  71. }
  72. av_packet_unref(&pkt);
  73. }
  74. avformat_close_input(&ctx);
  75. fprintf(stdout, "test finish\n");
  76. return 0;
  77. }

Linux下执行结果如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlbmdiaW5nY2h1bg_size_16_color_FFFFFF_t_70

GitHub:https://github.com/fengbingchun/OpenCV_Test

发表评论

表情:
评论列表 (有 0 条评论,1045人围观)

还没有评论,来说两句吧...

相关阅读