FFmpeg gets the web camera data decoded

  • 2020-06-19 11:04:04
  • OfStack

Real-time coding of the USB camera was discussed earlier. In this change of thought, we tried to intercept the H264 stream of the webcam and play it decoded.

The test code here is based on the Haikang camera.

The general flow of decoding remains the same as before, except that some functions are added.

FFmpeg opens the media file and views the information for the media file in three steps:

[

avformat_open_input;

avformat_find_stream_info;

av_dump_format;

]

By calling each of the three functions in turn, we can get a clear picture of the flow.

Complete code:


#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;// The structure of the body AVFormatContext: Contains many code stream parameters 
 
 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";// The path to get the code stream 
 
 av_register_all();// Register the codec 
 avformat_network_init();// loading socket Libraries and libraries related to network encryption protocol 
 
 if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)// Open multimedia data and get information 
 {
 return -1;
 }
 
 if (avformat_find_stream_info(pFormatCtx, NULL) < 0)// Read audio and video data and get information 
 {
 return -1;
 }
 
 av_dump_format(pFormatCtx, 0, argv[1], false);// Manual debugging function, see pFormatCtx->streams The content of the 
 
 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);// Find decoder 
 
 if (pCodec == NULL)
 {
 return -1;
 }
 
 if (avcodec_open2(pCodecCtx, pCodec, 0) < 0)// Initialize the AVCodecContext
 {
 return -1;
 }
 
 if (pCodecCtx->time_base.num > 1000 && pCodecCtx->time_base.den == 1)
 {
 pCodecCtx->time_base.den = 1000;
 }
 
 pFrame = av_frame_alloc();// Allocate memory 
 pFrameRGB = av_frame_alloc();
 
 i = 0;
 while (1)
 {
 if (av_read_frame(pFormatCtx, &packet) >= 0)// Read frames of audio or video in a stream 1 frame 
 {
 if (packet.stream_index == videoStream)
 {
 ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);// To decode 
 if (ret < 0)
 {
  printf("Decode Error.( The decoding error )\n");
  return ret;
 }
 if (got_picture)// Decoded successfully, got_picture Returns any non-zero value 
 {
  if (first_time)
  {
  // Initialize the 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;
  }
 
  // Processing image data 
  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;
}

Queue function:


#include "queue.h"
#include <iostream>
 
using namespace std;
 
void result_push(result_link_type* result_link, result_node_datatype * result_node) // The operation of entrance 
{
 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) // The team operation 
{
 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;
 }
}

Queue function header file:


#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); // The operation of entrance 
struct result_node_datatype* result_pop(result_link_type* result_link);// The team operation 
 
#endif

The decoded data is queued, removed from the queue, and displayed using opencv (opencv is displayed as another thread function).

admin:jdh123456@10.170.6.187 here is the name of the camera and the IP address.

Test code download: Click the open link


Related articles: