对USB摄像头实时编码,在前面已经探讨过了。这次改变下思路,尝试去截取网络摄像头的H264码流,将其解码播放。
这里的测试代码,是在海康摄像头的基础上进行的。
解码的大致流程和以前的保持一致,只不过增加了部分函数。
FFmpeg打开媒体文件并查看媒体文件的信息,有三个步骤:
avformat_open_input;
avformat_find_stream_info;
av_dump_format;
依次调用三个函数后,我们可以很清楚的知道码流的各种信息。
完整的代码:
#include <stdio.h> #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <windows.h> #include "queue.h" extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> } #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib ,"swscale.lib") using namespace std; using namespace cv; DWORD WINAPI opencv_imshow(LPVOID lparam) { result_link_type* result_link = (result_link_type*)lparam; struct result_node_datatype *result_node2 = NULL; while (1) { result_node2 = result_pop(result_link); if (result_node2 == NULL) { Sleep(1); continue; } imshow("frame", result_node2->result); waitKey(1); } } int main(int argc, const char * argv[]) { HANDLE thread1; result_link_type *result_link = new result_link_type; result_link->head = result_link->end = NULL; result_link->result_num = 0; thread1 = CreateThread(NULL, 0, opencv_imshow, (LPVOID)result_link, 0, NULL); int i; int videoStream; int frameFinished; int numBytes; int ret; int got_picture; long prepts = 0; bool first_time = true; AVCodec *pCodec; AVFrame *pFrame; AVFrame *pFrameRGB; AVPacket packet; AVCodecContext *pCodecCtx; AVFormatContext *pFormatCtx = NULL;//结构体AVFormatContext:包含码流参数较多 static struct SwsContext *img_convert_ctx; uint8_t *buffer; Mat pCvMat; char filepath[] = "rtsp://admin:jdh123456@10.170.6.187/axis-media/media.amp?camera=2";//码流的获取路径 av_register_all();//注册编解码器 avformat_network_init();//加载socket库以及网络加密协议相关的库 if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)//打开多媒体数据并且获得信息 { return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//读取视音频数据并且获得信息 { return -1; } av_dump_format(pFormatCtx, 0, argv[1], false);//手工调试函数,看到pFormatCtx->streams的内容 videoStream = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } } if (videoStream == -1) { return -1; } pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器 if (pCodec == NULL) { return -1; } if (avcodec_open2(pCodecCtx, pCodec, 0) < 0)//初始化AVCodecContext { return -1; } if (pCodecCtx->time_base.num > 1000 && pCodecCtx->time_base.den == 1) { pCodecCtx->time_base.den = 1000; } pFrame = av_frame_alloc();//分配内存 pFrameRGB = av_frame_alloc(); i = 0; while (1) { if (av_read_frame(pFormatCtx, &packet) >= 0)//读取码流中的音频若干帧或者视频一帧 { if (packet.stream_index == videoStream) { ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);//开始解码 if (ret < 0) { printf("Decode Error.(解码错误)\n"); return ret; } if (got_picture)//解码成功,got_picture返回任意非零值 { if (first_time) { //初始化SwsContext img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); if (img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context!\n"); exit(1); } numBytes = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); buffer = (uint8_t *)av_malloc(numBytes); avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); // allocator memory for BGR buffer pCvMat.create(cv::Size(pCodecCtx->width, pCodecCtx->height), CV_8UC3); first_time = false; } //处理图像数据 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); memcpy(pCvMat.data, buffer, numBytes); struct result_node_datatype *result_node = new struct result_node_datatype; result_node->result = pCvMat; result_push(result_link, result_node); } } av_free_packet(&packet); } } //free(buffer); av_free(buffer); av_free(pFrameRGB); av_free(pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); system("Pause"); return 0; }
队列函数:
#include "queue.h" #include <iostream> using namespace std; void result_push(result_link_type* result_link, result_node_datatype * result_node) //入队操作 { if (result_link->head == NULL) { result_link->head = result_node; result_link->end = result_link->head; result_link->result_num++; } else { result_link->end->next = result_node; result_link->end = result_node; result_link->result_num++; } } struct result_node_datatype* result_pop(result_link_type* result_link) //出队操作 { struct result_node_datatype* tmp_node; if (result_link->head == NULL) return NULL; else if (result_link->head == result_link->end) { return NULL; } else { tmp_node = result_link->head; result_link->head = result_link->head->next; result_link->result_num--; return tmp_node; } }
队列函数的头文件:
#ifndef QUEUE_H #define QUEUE_H #include <stdio.h> #include <stdlib.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; typedef struct result_link_datatype { struct result_node_datatype *head; struct result_node_datatype *end; int result_num; }result_link_type; struct result_node_datatype { Mat result; struct result_node_datatype* next; }; void result_push(result_link_type* result_link, result_node_datatype * result_node); //入队操作 struct result_node_datatype* result_pop(result_link_type* result_link);//出队操作 #endif
解码后的数据进入队列,再从队列中取出,利用opencv将其显示(opencv显示是另外开的一个线程函数)。
admin:jdh123456@10.170.6.187,这里是摄像头的名称和IP地址。
测试代码下载:点击打开链接
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我目前正在做一个项目,从网络摄像头捕捉视频,并通过UDP发送编码流来做实时流。 有人说从cap.read得到的帧已经是解码帧,我不知道这是如何以及何时发生的。我想要的是编码的帧或流。我应该怎么做才能得到它?我应该再编码一次吗?
问题内容: 如何连续从摄像头捕获图像? 我想尝试对象识别(也许使用Java Media Framework)。 我当时正在考虑创建两个线程 一个线程: 节点1:捕获实时图像 节点2:将图片另存为“ 1.jpg” 节点3:等待5秒 节点4:重复… 其他线程: 节点1:等到捕获图像 节点2:使用“ 1.jpg”获取每个像素的颜色 节点3:将数据保存在数组中 节点4:重复… 问题答案: 此JavaCV实
对于我正在进行的计算机视觉项目,我需要使用Logitech C920网络摄像头抓取图像。我使用OpenCV的视频捕获来实现这一点,但我面临的问题是,我在某个时刻拍摄的图像没有显示相机看到的最新情况。也就是说,如果我在时间戳t处拍摄一张图像,它显示了相机在时间戳(t-delta)处看到的东西,也就是说。 为此,我编写了一个程序,使计数器递增并在屏幕上显示。我把相机对准屏幕,让它录下来。当计数器达到某
我对Api非常陌生,我们的用例是将实时数据从网络摄像头流到kinesis视频流。步骤:在aws上创建ubuntu服务器并安装CPP SDK。在aws中创建了kinesis视频流,下载并在本地安装了Gstreamer。 我试图将rtsp示例数据放到Ec2ubuntu服务器上的gstream中,我运行的查询$gst-launch-1.0rtspsrc location=“rtsp://yourcame
我的jfreeChart来自网络摄像头的帧。我通过这个框架,它生成一个图形的R,G和B颜色的这个框架。我想这个图表做自动更新,因为我通过帧。我什么都试过了,但都没用。 }
我正在开发一个web应用程序,它可以浏览和拍摄本地照片,我还想通过相机拍摄图像。我使用下面的代码,我可以捕捉设备摄像头。 现在,我想获得图像和onchangeevent,转换为base64,并希望在该页面中显示。 好心帮我伙计们!