FFmpeg获取网络摄像头数据解码

对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地址。

测试代码下载:点击打开链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 利用ffmpeg命令行转压视频示例代码

    在开始本文的正文之前,首先得安装好ffmpeg程序(Linux下还得安装x264编码).Mac下直接用brew安装: brew install ffmpeg --with-faac --with-fdk-aac --with-ffplay --with-fontconfig --with-freetype --with-libass --with-libbluray --with-libcaca --with-libsoxr --with-libquvi --with-frei0r --with

  • python整合ffmpeg实现视频文件的批量转换

    转换工具层出不穷,ffmpeg才是全能的转换工具,只是不支持图形操作. 没有关系,命令行方式,在freebsd/linux下直接来 我们的思路是,设定一个文件夹存放源视频文件,python读取该文件夹下的全部文件,并对文件通过ffmpeg进行分析,根据需要,修改目标文件的编码.分辨率等等,调用ffmpeg转换. 我这次的需求是,我家液晶电视只支持分辨来,长宽均小于720,编码只支持divx/xvid的avi文件,且fps只能小于25--多次实践,才总结出来的,电视说明书也没说!! 下面的程序将

  • python+ffmpeg批量去视频开头的方法

    用来批量切割视频的开头部分,比如去掉一部电视剧的序幕,看着难受不说数量还很多,很菜鸟的一篇,毕竟我也是一个菜鸟,首先要有ffmpeg这个软件,安装什么的就不说了,网上一搜就出来了,直接给代码,以后丢了也不怕.自用的,没写那么多 #/usr/bin/python #coding:u8 import os pp=os.getcwd() path=''#视频所在目录 time=''#格式为hh:mm:ss[.xxx]的形式 for i in os.listdir(path): os.system("&

  • python opencv 读取本地视频文件 修改ffmpeg的方法

    Python + opencv 读取视频的三种情况: 情况一:通过摄像头采集视频 情况二:通过本地视频文件获取视频 情况三:通过摄像头录制视频,再读取录制的视频 摄像头采集.本地视频文件的读取.写视频文件,网上都有代码. 我发现情况一和情况三都没有问题,大家注意读取自己通过摄像头录制的视频文件是没有问题的.但读取其他视频都会发现帧率为0(如果你获取视频的帧率并打印出来的话),并且退出读取.这时候读取是不成功的. 进去正题:如何解决读取视频失败的情况.这个问题很普遍,以至在官方教程的程序下面都提示

  • FFmpeg获取网络摄像头数据解码

    对USB摄像头实时编码,在前面已经探讨过了.这次改变下思路,尝试去截取网络摄像头的H264码流,将其解码播放. 这里的测试代码,是在海康摄像头的基础上进行的. 解码的大致流程和以前的保持一致,只不过增加了部分函数. FFmpeg打开媒体文件并查看媒体文件的信息,有三个步骤: avformat_open_input: avformat_find_stream_info: av_dump_format: 依次调用三个函数后,我们可以很清楚的知道码流的各种信息. 完整的代码: #include <st

  • Python利用PyQt5制作一个获取网络实时数据NBA数据播报GUI功能

    制作NBA数据爬虫 捋顺思路 我们在这里选择的是百度体育带来的数据,我们在百度当中直接搜索NBA跳转到网页,我们可以看到,百度已经为我们提供了相关的数据 我们点击进去后,可以发现这是一个非常简洁的网址 我们看一下这个地址栏,发现毫无规律https://tiyu.baidu.com/live/detail/576O5Zu955S35a2Q6IGM5Lia56%2Bu55CD6IGU6LWbI2Jhc2tldGJhbGwjMjAyMS0wNi0xMyPniLXlo6t2c%2BWspritq%2Bi

  • Android Studio获取网络JSON数据并处理的方法

    本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下 1.需要的网络JSON数据 2.数据实现类 package chenglong.activitytest.pengintohospital.entity; import org.json.JSONException; import org.json.JSONObject; /** * * 科室 * Created by LICHENGLONG on 2017-10-02. */ public class Bas

  • python实现从本地摄像头和网络摄像头截取图片功能

    python-----从本地摄像头和网络摄像头截取图片 ,具体代码如下所示: import cv2 # 获取本地摄像头 # folder_path 截取图片的存储目录 def get_img_from_camera_local(folder_path): cap = cv2.VideoCapture(0) i = 1 while True: ret, frame = cap.read() cv2.imshow("capture", frame) print str(i) cv2.imw

  • Nodejs获取网络数据并生成Excel表格

    Nodejs的模版中有很多关于Excel表格的,这里我简单介绍一下我使用过的一个模块的使用. 首先,先安装Excel的模块: npm install node-xlsx 然后,在代码中引入模块: var xlsx = require('node-xlsx'); 最后,获取数据并写入Excel: var fs = require('fs'); var xlsx = require('node-xlsx'); var ajax = require('./ajax.js'); start(); fun

  • HttpURLConnection和okHttp两种获取网络数据的实现方法

    废话少说,直接上代码.简单易懂. xml如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id

  • python如何获取网络数据

    Retrieving Data over HTTP Python 内置了 sockets 可以实现与网络连接并通过 Python 提取数据的功能. socket 是可以提供双向连接的,我们可以对同一个 socket 进行读写操作.比方说,A 对 socket 写入信息,并且将其发送给 socket 连接另一端 B:那么 B 读取 socket 的内容就可以得到 A 的信息.但是这样会有一个问题,比如说, A端并没有发送任何信息,而 B 端一直在尝试读取 socket 的内容,那么 A 端和 B

  • Python利用PyQt5制作一个获取网络实时NBA数据并播报的GUI程序

    制作NBA数据爬虫 捋顺思路 我们在这里选择的是百度体育带来的数据,我们在百度当中直接搜索NBA跳转到网页,我们可以看到,百度已经为我们提供了相关的数据 我们点击进去后,可以发现这是一个非常简洁的网址 我们看一下这个地址栏,发现毫无规律https://tiyu.baidu.com/live/detail/576O5Zu955S35a2Q6IGM5Lia56%2Bu55CD6IGU6LWbI2Jhc2tldGJhbGwjMjAyMS0wNi0xMyPniLXlo6t2c%2BWspritq%2Bi

  • Android网络编程之获取网络上的Json数据实例

    为要获取网络上的Json所以需要服务器端提供的支持. 一.创建服务器端: 服务器端项目结构: 服务器端运行效果图: 第一步:创建业务所需的JavaBean 复制代码 代码如下: package com.jph.sj.model;   import java.util.Date;   /**  * 新闻实体类  * @author jph  * Date:2014.09.26  */ public class News {     private Integer id;     private S

  • iOS获取网络类型的方法汇总

    Reachability类只能区分WIFI和WWAN类型,却无法区分2G网和3G网. 网上也有些方法,却都存在Bug. 经过网上查找资料和测试,基本上总结了以下几种方法: 1.使用导航栏的方式:(私有API) 代码: 复制代码 代码如下: typedef enum {     NetWorkType_None = 0,     NetWorkType_WIFI,     NetWorkType_2G,     NetWorkType_3G, } NetWorkType; UIApplicatio

随机推荐