項(xiàng)目地址源碼https://github.com/liluojun/PlayVideo
之前弄了下Android硬解H264https://blog.csdn.net/hjt505694246/article/details/105046233撤奸,但是硬解多少還是受到硬件影響所有再折騰下ffmpeg軟解第岖。
關(guān)于ffmpeg解碼的文章很多我也是業(yè)余接觸下并且我對(duì)C語言也是個(gè)初學(xué)者宣肚,有不足的地方還請(qǐng)見諒。
先上代碼
先初始化解碼器
int FFmpegEncode::creatFFmpeg(AVCodecID id) {
avcodec_register_all();
mAVCodec = avcodec_find_decoder(id);
if (mAVCodec == NULL) {
printf("mAVCodec==NULL\n");
return -1;
}
mAVCodecContext = avcodec_alloc_context3(mAVCodec);
if (mAVCodecContext == NULL) {
printf("mAVCodecContext==NULL\n");
return -1;
}
if (avcodec_open2(mAVCodecContext, mAVCodec, NULL) < 0) {
printf("avcodec_open2 error\n");
return -1;
}
mAVFrame = av_frame_alloc();
if (!mAVFrame) {
printf("av_frame_alloc error\n");
return -1;
}
mAVPacket = av_packet_alloc();
if (!mAVPacket) {
printf("av_packet_alloc error\n");
return -1;
}
av_init_packet(mAVPacket);
return 0;
}
設(shè)置解碼參數(shù):寬高、幀率、數(shù)據(jù)類型
int FFmpegEncode::initAVCodecContext(int width, int heigth, int fps, AVPixelFormat pixFmt) {
if (mAVCodecContext == NULL) {
printf("initAVCodecContext NULL\n");
return -1;
}
if (width <= 0 || heigth <= 0 || fps <= 10) {
printf("initAVCodecContext Parameters of the abnormal\n");
return -1;
}
mAVCodecContext->width = width;
mAVCodecContext->height = heigth;
mAVCodecContext->frame_bits = fps;
mAVCodecContext->pix_fmt = pixFmt;
return 0;
}
喂數(shù)據(jù)解碼:framedata是源數(shù)據(jù)赊锚,*outputY,*outputU,*outputV是解碼后的yuv三個(gè)分量數(shù)據(jù),pixfmt數(shù)據(jù)類型屉栓。
這里我有個(gè)拷貝的動(dòng)作舷蒲,據(jù)說有零拷貝的方式,有木有大佬知道的可以指點(diǎn)一下友多。
int FFmpegEncode::encodeFFmpeg(uint8_t *framedata, int framelen,//input
uint8_t *outputY, uint8_t *outputU, uint8_t *outputV, int *width,
int *height,
AVPixelFormat pixfmt) {
if (mAVPacket == NULL) {
printf("encodeFFmpeg NULL\n");
return -1;
}
mAVPacket->data = framedata;
mAVPacket->size = framelen;
while (mAVPacket->size > 0) {
if (avcodec_send_packet(mAVCodecContext, mAVPacket)) {
printf("%s %d avcodec_send_packet fail\n", __func__, __LINE__);
return -2;
}
if (avcodec_receive_frame(mAVCodecContext, mAVFrame)) {
printf("%s %d avcodec_receive_frame fail\n", __func__, __LINE__);
return -3;
}
switch (mAVCodecContext->pix_fmt) {
case AV_PIX_FMT_YUV420P: {
memcpy(outputY, mAVFrame->data[0], *width * *height);
memcpy(outputU, mAVFrame->data[1], *width * *height / 4);
memcpy(outputV, mAVFrame->data[2], *width * *height / 4);
width = &(mAVCodecContext->width);
height = &(mAVCodecContext->height);
pixfmt = mAVCodecContext->pix_fmt;
break;
}
case AV_PIX_FMT_NV21: {
memcpy(outputY, mAVFrame->data[0], *width * *height);
memcpy(outputU, mAVFrame->data[1], *width * *height / 4);
memcpy(outputV, mAVFrame->data[2], *width * *height / 4);
width = &(mAVCodecContext->width);
height = &(mAVCodecContext->height);
pixfmt = mAVCodecContext->pix_fmt;
break;
}
default: {
printf("mAVCodecContext->pix_fmt Failure to identify\n");
return -4;
}
}
return 0;
}
}
釋放解碼器資源
void
FFmpegEncode::unEncode() {
avcodec_close(mAVCodecContext);
av_free(mAVCodecContext);
av_frame_free(&mAVFrame);
}