根据decoder.h头文件在h264.decode中创建回调函数callback

lihong398090509 2014-11-29 10:19:51
Decoder.h


#ifndef DECODER_H_
#define DECODER_H_

#ifdef WIN32
# include <Windows.h>
# ifdef DECODER_RDZC_EXPORTS
# define DECODER_EXPORTS _declspec(dllexport)
# else
# define DECODER_EXPORTS _declspec(dllimport)
# endif
#else
# define DECODER_EXPORTS
#endif

//解码器句柄类型
typedef int DecoderHandle;

typedef enum _ProtType
{
PROT_RTP=0,
PROT_PRVT,
PROT_RAW,
PROT_RTPRTSP,
PROT_MAX
}ProtType;


//视频编码方式
typedef enum _VideoCodecType
{
VIDEO_CODEC_TYPE_NONE = 4,
VIDEO_CODEC_TYPE_H264, //H264编码
VIDEO_CODEC_TYPE_H264_RTP, //RTP-H264
VIDEO_CODEC_TYPE_JPEG2000, //JPEG2000编码
VIDEO_CODEC_TYPE_LZW, //LZW编码
VIDEO_CODEC_TYPE_YUV, //不进行编码,YUV原始数据
VIDEO_CODEC_TYPE_MAX
}VideoCodecType;

//视频数据的格式
typedef enum _VideoFormat
{
VIDEO_FORMAT_NONE = 0,
VIDEO_FORMAT_UYVY422, /// packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
VIDEO_FORMAT_YUV420P, ///planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
}VideoFormat;

//音频编码方式
typedef enum _AudioCodecType
{
AUDIO_CODEC_TYPE_NONE = 0, //不进行编码
AUDIO_CODEC_TYPE_AAC = 1, //AAC编码
AUDIO_CODEC_TYPE_G711U = 2, //G711U编码
AUDIO_CODEC_TYPE_G711A = 3, //G711A编码
AUDIO_CODEC_TYPE_PCM = 4, //不进行编码,PCM原始数据
AUDIO_CODEC_TYPE_MAX,
}AudioCodecType;

//视频解码后的信息
typedef struct _VideoDecodeInfo
{
unsigned char* pBuffer; //解码后的Yuv格式的缓冲区指针
int nLen; //解码后的Yuv格式缓冲区的长度
int nWidth; //画面宽,单位为像素
int nHeight; //画面高,单位为像素
int nStamp; //时标信息,单位毫秒
int nYear; //年
int nMonth; //月
int nDay; //日
int nFrameRate; //编码时产生的图像帧率
VideoFormat nVideoFormat; //视频格式
void* pUserData; //SetDecoderCallback设置的pUserData
}VideoDecodeInfo;

//音频解码后的信息
typedef struct _AudioDecodeInfo
{
unsigned char* pBuffer; //音频解码后的缓冲区指针
int nLen; //音频解码后缓冲区的长度
int nChannels; //通道数
int nSampleRate; //采样率
int nBit; //位数
void* pUserData; //SetDecoderCallback设置的pUserData
}AudioDecodeInfo;

//流信息
typedef struct _StreamInfo
{
VideoCodecType nVideoCodec; //视频编码方式
int nVideoWidth; //视频宽
int nVideoHeight; //视频高
int nVideoFrameRate; //帧率
VideoFormat nInputVideoFormat; //输入的YUV视频格式,在m_nVideoCodec为VIDEO_CODEC_TYPE_YUV时有效
VideoFormat nOutputVideoFormat; //解码后的视频格式
ProtType nProtocolType; //视频协议类型
AudioCodecType nAudioCodec; //音频编码方式
int nAudioChannels; //通道数
int nAudioSampleRate; //采样率
}StreamInfo;

//解析后的压缩流信息
typedef struct _ESInfo
{
unsigned int nTimeStamp;
unsigned char* pBuffer;
int nLen;
void* pUserData;
}ESInfo;

/*视频解码一帧的回调函数
@param hHandle 解码器句柄
@param pVideoDecodeInfo 视频帧信息
*/
typedef void (* VideoDecodeCallback)(DecoderHandle hHandle,VideoDecodeInfo* pVideoDecodeInfo);

/*音频解码的回调函数
@param hHandle 解码器句柄
@param pAudioDecodeInfo 音频帧信息
*/
typedef void (* AudioDecodeCallback)(DecoderHandle hHandle,AudioDecodeInfo* pAudioDecodeInfo);

/*音频解码的回调函数
@param hHandle 解码器句柄
@param pAudioDecodeInfo 音频帧信息
*/
typedef void (* EncodedStreamCallback)(DecoderHandle hHandle,ESInfo* pESInfo);

#ifdef __cplusplus
extern "C"{
#endif

/*打开解码器
@param pStreamInfo 流信息
@return 成功返回解码器句柄,失败返回-1
*/
DECODER_EXPORTS DecoderHandle OpenDecoder(StreamInfo* pStreamInfo);

/*设置解码的回调函数
@param hHandle 解码器句柄
@param pVideoDecodeCallback 视频解码的回调函数
@param pAudioDecodeCallback 音频解码的回调函数
@param pUserData 回调函数中用到的pUserData
@return 成功返回0,失败返回-1
*/
DECODER_EXPORTS int SetDecoderCallback(DecoderHandle hHandle,
VideoDecodeCallback pVideoDecodeCallback,
AudioDecodeCallback pAudioDecodeCallback,
EncodedStreamCallback pEncodedStreamCallback,
void* pUserData);

/*输入待解码的流数据
@param hHandle 解码器句柄
@param pBuffer 编码缓冲区指针
@param nLen 编码缓冲区长度
@return 成功返回0,失败返回-1
@注: 一个解码库实例仅支持输入一个流数据。
*/
DECODER_EXPORTS int InputStreamData(DecoderHandle hHandle,unsigned char* pBuffer,int nLen);

//关闭解码器,成功返回0,失败返回-1
/*关闭解码器
@param hHandle 解码器句柄
@return 成功返回0,失败返回-1
*/
DECODER_EXPORTS int CloseDecoder(DecoderHandle hHandle);
#ifdef __cplusplus
}
#endif

#endif


h264decode
#include "stdafx.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


#ifdef __cplusplus
extern "C"
{
#endif
#include "libavutil/avutil.h"
#include "libavcodec/avcodec.h" //ffmpeg是C程序,许添加C字符
};

#define INBUF_SIZE (4096)
static void SaveYuv(unsigned char *buf, int wrap, int xsize, int ysize, FILE *f)
{
int i;
//buf += 64;
//fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
for (i = 0; i<ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
}//存储YUV格式
static int _find_head(unsigned char *buffer, int len)
{
int i; int j;
for (i = 512; i<len; i++)
{
if (buffer[i] == 0 && buffer[i + 1] == 0 && buffer[i + 2] == 0 && buffer[i + 3] == 1)
break;
}
if (i == len)
return 0;
if (i == 512)
return 0;
return i;
}
#define FILE_READING_BUFFER (1*1024*1024)
static void build_avpkt(AVPacket *avpkt, FILE *fp)
{
#if 0
int len;
static unsigned char buffer[INBUF_SIZE];
len = fread(buffer, 1, INBUF_SIZE, fp);
avpkt->data = buffer;
avpkt->size = len;
#else
static unsigned char buffer[1 * 1024 * 1024];
static int readptr = 0;
static int writeptr = 0;
int len, toread;
int nexthead;
if (writeptr - readptr < 200 * 1024)
{
memmove(buffer, &buffer[readptr], writeptr - readptr);
writeptr -= readptr;
readptr = 0;
toread = FILE_READING_BUFFER - writeptr;
len = fread(&buffer[writeptr], 1, toread, fp);
writeptr += len;
}
nexthead = _find_head(&buffer[readptr], writeptr - readptr);
if (nexthead == 0)
{
printf("failed find next head...\n");
nexthead = writeptr - readptr;
}
avpkt->size = nexthead;
avpkt->data = &buffer[readptr];
readptr += nexthead;
#endif
}
static void video_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c = NULL;
int frame, got_picture, len;
FILE *f, *fout;
AVFrame *picture;
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
char buf[1024];
AVPacket avpkt;

av_init_packet(&avpkt); //使用默认值初始化avpacket
memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);

printf("Video decoding\n");
//opts = NULL;

/* find the H264 video decoder */
codec = avcodec_find_decoder(CODEC_ID_H264); //查找对应解码器
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}

c = avcodec_alloc_context3(codec); //分配编码解码器上下文
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}


if (codec->capabilities&CODEC_CAP_TRUNCATED) //判断是否为完整帧
c->flags |= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */


/* open it */
if (avcodec_open2(c, codec, NULL) < 0) { //打开解码器
fprintf(stderr, "could not open codec\n");//stderr,标准输出(设备)文件,对应终端的屏幕
//将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。在C中,程序执行时,一直处于开启状态。
exit(1);
}
fout = fopen(outfilename, "wb"); //这边比原代码添加一个输出的文件
/* the codec gives us the frame size, in samples */
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}

picture = avcodec_alloc_frame();//给视频帧分配空间以便存储解码后的图片
if (!picture) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}// 确认所需缓冲区大小并且分配缓冲区空间

frame = 0;

for (;;) {
//avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
build_avpkt(&avpkt, f); //要按它的帧来读。
if (avpkt.size == 0)
break;




while (avpkt.size > 0)
{
len = avcodec_decode_video2(c, picture, &got_picture, &avpkt); //解码视频
if (len < 0) {
fprintf(stderr, "Error while decoding frame %d\n", frame);
break;
// exit(1);
}
if (got_picture)
{
printf("saving frame %3d\n", frame);
fflush(stdout);//刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上

sprintf(buf, outfilename, frame); //sprintf()把格式化的数据写入字符串缓冲区

SaveYuv(picture->data[0], picture->linesize[0],
c->width, c->height, fout); //按照对应YUV格式将数据保存到输出文件
SaveYuv(picture->data[1], picture->linesize[1],
c->width / 2, c->height / 2, fout);
SaveYuv(picture->data[2], picture->linesize[2],
c->width / 2, c->height / 2, fout);
frame++;
}
avpkt.size -= len;
avpkt.data += len;
}
}



avpkt.data = NULL;
avpkt.size = 0;
len = avcodec_decode_video2(c, picture, &got_picture, &avpkt); //解码视频
if (got_picture) {
printf("saving last frame %3d\n", frame);
fflush(stdout);

sprintf(buf, outfilename, frame);

SaveYuv(picture->data[0], picture->linesize[0], c->width, c->height, fout);
SaveYuv(picture->data[1], picture->linesize[1], c->width / 2, c->height / 2, fout);
SaveYuv(picture->data[2], picture->linesize[2], c->width / 2, c->height / 2, fout);
frame++;
}
fclose(f);
fclose(fout);
avcodec_close(c);
av_free(c);
av_free(picture);
printf("\n");
printf("执行完毕\n");
system("pause");
}

int _tmain(int argc, _TCHAR* argv[])
{
avcodec_register_all();
video_decode_example("test.yuv", "test.h264");
return 0;
}

对于callback不是很了解,一直没看懂,希望各位帮忙修改下程序,实现回调函数
...全文
380 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧