在自定义协议的时候,提取连续的媒体数据
#define BUFSIZE 1024 * 4 // 经典大小
// int (*read_packet)(void *opaque, uint8_t *buf, int buf_size)
int read_packet(void *opaque, uint8_t *buf, int bufSize)
{
FILE *inFile = (FILE *)opaque;
int readSize = fread(buf, 1, bufSize, inFile);
av_log(NULL, AV_LOG_DEBUG, "[%s] readSize:%d, buf_size:%d\n -- line:%d", __FUNCTION__, readSize, bufSize, __LINE__);
if (readSize <= 0) // 数据读取完毕
return AVERROR_EOF;
return readSize;
}
int AVIO_decodeVideoInterface(AVCodecContext *decoderCtx, AVPacket *packet, AVFrame *frame, FILE *dest_fp)
{
int ret = avcodec_send_packet(decoderCtx, packet);
if (ret == AVERROR(EAGAIN))
{
av_log(NULL, AV_LOG_WARNING, "[%s] Receive_frame and send_packet both returned EAGAIN,which is an API violation. -- line:%d\n", __FUNCTION__, __LINE__);
}
else if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avcodec_send_packet failed! -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
if (!packet)
{
av_log(NULL, AV_LOG_INFO, "[%s] get flush frame -- line:%d \n", __FUNCTION__, __LINE__);
}
while (avcodec_receive_frame(decoderCtx, frame) >= 0)
{
size_t dataSize = av_get_bytes_per_sample(decoderCtx->sample_fmt);
if (dataSize < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] get bytes failed! -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
av_log(NULL, AV_LOG_DEBUG, "[%s] sample rate: %d HZ, channels: %d, pixformat:%u -- line:%d\n", __FUNCTION__, frame->sample_rate, frame->channels, frame->format, __LINE__);
// 这里只是针对是planar格式的转换,并不通用
for (int i = 0; i < frame->nb_samples; i++)
{
for (int channel = 0; channel < decoderCtx->channels; channel++)
{
size_t writeSize = fwrite(frame->data[channel] + dataSize * i, 1, dataSize, dest_fp);
if (writeSize <= 0 || writeSize != dataSize)
{
av_log(NULL, AV_LOG_ERROR, "[%s] write file failed! -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
}
}
}
}
int AVIO_decodeVideo(const char *inFileName, const char *outFileName)
{
FILE *inFile = fopen(inFileName, "rb");
FILE *outFile = fopen(outFileName, "wb");
if (!inFile || !outFile)
{
av_log(NULL, AV_LOG_ERROR, "[%s] open outfile:%s or %s failed! -- line:%d\n", __FUNCTION__, outFileName, inFileName, __LINE__);
goto _end;
}
// 自定义 IO
uint8_t *ioBuffer = av_malloc(BUFSIZE);
if (!ioBuffer)
{
av_log(NULL, AV_LOG_ERROR, "[%s] malloc ioBuffer failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
/**
* ioBuffer -- Memory block for input/output operations via AVIOContext.
* The buffer must be allocated with av_malloc() and friends
* It may be freed and replaced with a new buffer by libavformat.
* AVIOContext.buffer holds the buffer currently in use,
* which must be later freed with av_free().
*/
/**
* BUFSIZE -- The buffer size is very important for performance.
* For protocols with fixed blocksize it should be set to this blocksize.
* For others a typical size is a cache page, e.g. 4kb.
*/
/**
* (void *)inFile -- An opaque pointer to user-specific data
*/
/**
* read_packet -- A function for refilling the buffer, may be NULL.
* For stream protocols, must never return 0 but rather a proper AVERROR code.
*/
AVIOContext *avioCtx = avio_alloc_context(ioBuffer, BUFSIZE, 0/*读数据是0 写数据是1*/, (void *)inFile, read_packet, NULL, NULL);
if (!avioCtx)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avio alloc context failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
AVFormatContext *fmtCtx = avformat_alloc_context();
if (!fmtCtx)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avformat alloc context failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
fmtCtx->pb = avioCtx;
int ret = avformat_open_input(&fmtCtx, NULL, NULL, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avformat open input failed%s -- line:%d\n", __FUNCTION__, av_err2str(ret), __LINE__);
goto _end;
}
// 编码器查找
AVCodec *decoder = avcodec_find_decoder(AV_CODEC_ID_AAC);
if (!decoder)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avcodec find decoder failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
AVCodecContext *decoderCtx = avcodec_alloc_context3(decoder);
if (!decoderCtx)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avcodec alloc context3 failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
ret = avcodec_open2(decoderCtx, decoder, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avcodec open2 failed:%s! -- line:%d\n", __FUNCTION__, av_err2str(ret), __LINE__);
goto _end;
}
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
if (!packet || !frame)
{
av_log(NULL, AV_LOG_ERROR, "[%s] av packet or frame alloc failed! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
while (av_read_frame(fmtCtx, packet) >= 0)
{
AVIO_decodeVideoInterface(decoderCtx, packet, frame, outFile);
}
av_log(NULL, AV_LOG_INFO, "[%s] read file finish-- line:%d\n", __FUNCTION__, __LINE__);
AVIO_decodeVideoInterface(decoderCtx, NULL, frame, outFile);
_end:
if (inFile)
fclose(inFile);
if (outFile)
fclose(outFile);
if (packet)
av_packet_free(&packet);
if (fmtCtx)
avformat_close_input(&fmtCtx);
if (decoderCtx)
avcodec_free_context(&decoderCtx);
if (frame)
av_frame_free(&frame);
if (avioCtx)
avio_context_free(&avioCtx);
return ret;
}