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