将ts流flv流mp4流视频数据解码
这里main文件主要是执行了rkmedia_decoder_init 与decode_threads_init两个工作,其中第一个工作是初始化vdec模块(video decode)
//这是rv1126对视频数据进行解码的文件
#include <stdio.h>
// #include "video_queue.h"
using namespace std;
#include "rkmedia_module_config.h"
#include "video_queue.h"
video_queue *video_queue1 = new video_queue();
extern int rkmedia_decoder_init();
extern void decode_threads_init();
int main(int argc, char *argv[])
{rkmedia_decoder_init();decode_threads_init();while (1){/* code */}// while(1)// {// }return 0;
}
视频解码模块初始化如下:
RK_MPI_SYS_Init是初始化rkmdia模块之前必须要使用的
配置了解码模块H264、软件解码、帧格式的过程(通常来说我们选用帧解码而非流解码)
(在这一步时候我调试发现一直出现解码模块初始化失败的报错,后来发现是文件中其他的库可能放的不够或者放错了,编译是没问题的执行时一直报错VDEC Create失败)
int rkmedia_decoder_init()
{int ret;RK_MPI_SYS_Init();VDEC_CHN_ATTR_S vdec_attrs;vdec_attrs.enCodecType = RK_CODEC_TYPE_H264; //解码数据格式 H264vdec_attrs.enDecodecMode = VIDEO_DECODEC_SOFTWARE; //解码模式:软件解码 硬件解码vdec_attrs.enMode = VIDEO_MODE_FRAME; //数据格式 帧格式 流格式ret = RK_MPI_VDEC_CreateChn(0,&vdec_attrs);if(ret){printf("creat chnnel err!\r\n");printf("Create Vdec[0] failed! ret=%d\n", ret);return -1;}printf("vdec creat chnnel success!\r\n");return 0;
}
创建线程模块主要是创建了三个线程:
1.读取本地被编码的数据read_video_thread并存入队列
2.将队列内的数据转化为rkmedia能读懂的形式并输出到VDEC
3.从VDEC取出解码数据显示
#include<stdio.h>
#include<pthread.h>
pthread_t read_video_pid;
pthread_t send_video_decode_pid;
pthread_t display_video_pid;extern void *read_video_thread(void *arg);
extern void *send_video_decode_thread(void *arg);
extern void *display_video_thread(void *arg); void decode_threads_init()
{//读取本地编码后的视频文件到队列pthread_create(&read_video_pid,NULL,read_video_thread,NULL);// //取出队列中的编码后的视频文件送往解码器pthread_create(&send_video_decode_pid,NULL,send_video_decode_thread,NULL);// //显示解码后的数据pthread_create(&display_video_pid,NULL,display_video_thread,NULL);printf("decode threads creat success!\r\n");
}
read_video_thread:这个主要是调用了ffmpeg库来读取编码的数据
这里我总结了6步,打开文件、获取文件信息、获取流、获取编码器、获取编码器上下文并绑定、开始读取,这里其实与编码部分类似
#include <stdio.h>
//确保ffmpeg_include.h正确使用的预处理宏
#define __STDC_CONSTANT_MACROS
#define TS_FILE "video.ts"
// #include "include/ffmpeg_include.h"
#include "video_queue.h"
#include <stdlib.h>
#include<pthread.h>#define __STDC_CONSTANT_MACROS
extern "C"
{
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include "libavutil/time.h"
}
extern video_queue* video_queue1;/*1.打开文件2.获取文件信息3.获取对应流4.获取对应编码器5.分配编码器上下文并绑定编码器6.开始读取
*/
void *read_video_thread(void *arg) {pthread_detach(pthread_self());printf("----------------read_video_thread-------------\r\n");AVFormatContext *avfmt_context = NULL;//打开媒体文件并绑定信息到媒体上下文int ret = avformat_open_input(&avfmt_context, TS_FILE, NULL, NULL);if (ret < 0) {printf("avformat_open_input error\r\n");return NULL;}//寻找对应流文件avformat_find_stream_info(avfmt_context,nullptr); int numret = av_find_best_stream(avfmt_context,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);if(numret <0){printf("find best stream err!\r\n");avformat_free_context(avfmt_context);return NULL;} AVCodec *avcode = avcodec_find_decoder(avfmt_context->streams[numret]->codecpar->codec_id);AVCodecContext *avcodecontext = avcodec_alloc_context3(avcode);ret = avcodec_parameters_to_context(avcodecontext,avfmt_context->streams[numret]->codecpar);if(ret < 0){avcodec_free_context(&avcodecontext);printf("get code context err!\r\n");return NULL;} AVPacket *packet = av_packet_alloc();while(av_read_frame(avfmt_context,packet) >= 0){if(packet->stream_index == numret){video_data_packet_t *video_packet = (video_data_packet_t *)malloc(sizeof(video_data_packet_t));memcpy(video_packet->videobuff,packet->data,packet->size);video_packet->size = packet->size;video_queue1 ->putVideoPacketQueue(video_packet);}}// 释放资源if (avfmt_context) {avformat_close_input(&avfmt_context);}return NULL;
}
将队列内packet转化为rkmedia能识别的数据:
rkmedia会读取MEDIA_BUFFER类型的数据实质也就是void *,因此我们先分配了这样的MEDIA_BUFFER数据(这里可以理解MEDIA_BUFFER是一个画布,需要指定其框架大小后往里面填充数据),然后把我们的数据拷进去,大小也考进去,发送到VDEC最后释放
#include <stdio.h>
#include <cstdlib>
#include<pthread.h>
#include <stdlib.h>
#include "video_queue.h"
#include "rkmedia_buffer.h"
#include <string.h>
#include <rkmedia_api.h>extern video_queue* video_queue1;
//为什么要把mp4的packet放入队列再取出送到decoder?
//因为mp4的packet是普通的数据,而rv1126解码器需要读取特定类型的数据
/*1.取出数据2.创建画布3.复制信息4.发送数据5.释放信息*/
void *send_video_decode_thread(void *arg)
{free(arg);pthread_detach(pthread_self());MB_IMAGE_INFO_S image_info = {1920,1080,1920,1080,IMAGE_TYPE_NV12};MEDIA_BUFFER mb = NULL;// avformat_open_input();while(1){video_data_packet_t *video_packet = video_queue1->getVideoPacketQueue();//MEDIA_BUFFER就是视频模板 属性 是否硬件buffer 硬件buffer是否有缓冲区mb = RK_MPI_MB_CreateImageBuffer(&image_info,RK_TRUE,MB_FLAG_NOCACHED);memcpy(RK_MPI_MB_GetPtr(mb),video_packet->videobuff,video_packet->size);printf("size if %d\r\n",video_packet->size);RK_MPI_MB_SetSize(mb,video_packet->size);RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC,0,mb);RK_MPI_MB_ReleaseBuffer(mb);}return NULL;
}
显示模块,我没屏幕,没做,但是你可以建立一个线程然后RK_MPI_SYS_GetMediaBuffer得到数据然后RK_MPI_MB_GetImageInfo获取信息,打印出来看这个信息判断是否正常运行。