H264转成RGB24格式-2016.01.21

#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <android/log.h>

typedef enum
{
    FALSE = 0, TRUE = 1,
} C_BOOL;

typedef unsigned char uint8_t;

#define  IN_BUFFER_SIZE  2048
#define TARGET_VIDEO_TYPE AV_PIX_FMT_RGB565

#define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, "(>_<)", format, ##__VA_ARGS__)
#define LOGD(format, ...)  __android_log_print(ANDROID_LOG_DEBUG, "(-_-)", format, ##__VA_ARGS__)

static C_BOOL __DecodeH264Video(FILE* fp_in, FILE* fp_out);

JNIEXPORT jboolean JNICALL Java_com_zhoulee_h264decoder_MainActivity_DecodeH264Video(JNIEnv *env, jobject obj)
{
    char filepath_in[] = "/data/video/bxjg_352x288.h264";
    FILE *fp_in = fopen(filepath_in, "rb");
    if (NULL == fp_in)
    {
        LOGE("open input h264 video file failed, filename [%s]", filepath_in);
        return (jboolean) FALSE;
    }

    char filepath_out[] = "/data/video/bxjg_352x288.rgb565";
    FILE *fp_out = fopen(filepath_out, "wb");
    if (NULL == fp_out)
    {
        LOGE("open output rgb video file failed, filename [%s]", filepath_out);
        return (jboolean) FALSE;
    }

    LOGD("open input and output file success");

    if (TRUE == __DecodeH264Video(fp_in, fp_out))
    {
        LOGD("decode h264 video success");
    }
    else
    {
        LOGE("decode h264 video failed");
        return (jboolean) FALSE;
    }

    fclose(fp_in);
    fclose(fp_out);

    return (jboolean) TRUE;
}

typedef struct
{
    AVCodec *pCodec;
    AVCodecContext *pCodecCtx;
    AVCodecParserContext *pCodecParserCtx;
    AVFrame *pFrame;
    AVFrame *pRGBFrame;
    struct SwsContext *img_convert_ctx;
    uint8_t *out_buffer;
    uint8_t *cur_ptr;
    AVPacket packet;
    int cur_size;
    int first_time;
    int got_picture;
    int dst_bpp; //bytes of pixel of destination format
} H264DecodeHandler;

JNIEXPORT jint JNICALL Java_com_zhoulee_h264decoder_MainActivity_InitH264Decoder(JNIEnv *env, jobject obj)
{
    return 0;
}

int InitH264Decoder()
{
    H264DecodeHandler *handle = (H264DecodeHandler*) malloc(sizeof(H264DecodeHandler));
    if (NULL == handle)
    {
        LOGE("malloc H264DecodeHandler failed");
        return 0;
    }

    avcodec_register_all();
    handle->pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (NULL == handle->pCodec)
    {
        LOGE("avcodec_find_decoder failed");
        return 0;
    }

    handle->pCodecCtx = avcodec_alloc_context3(handle->pCodec);
    if (NULL == handle->pCodecCtx)
    {
        LOGE("avcodec_alloc_context3 failed");
        return 0;
    }

    handle->pCodecParserCtx = av_parser_init(AV_CODEC_ID_H264);
    if (NULL == handle->pCodecParserCtx)
    {
        LOGE("av_parser_init failed");
        return 0;
    }

    if (avcodec_open2(handle->pCodecCtx, handle->pCodec, NULL) < 0)
    {
        LOGE("avcodec_open2 failed");
        return 0;
    }

    handle->pFrame = av_frame_alloc();
    if (NULL == handle->pFrame)
    {
        LOGE("av_frame_alloc failed");
        return 0;
    }

    av_init_packet(&(handle->packet));

    handle->cur_size = 0;
    handle->got_picture = 0;
    handle->first_time = 1;
    handle->dst_bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(TARGET_VIDEO_TYPE)) / 8;

    LOGD("bytes of pixel of destination format is [%d]", handle->dst_bpp);

    return (int) handle;
}

void ReleaseH264Decoder(int decodeHandle)
{
    H264DecodeHandler* handle = (H264DecodeHandler*) decodeHandle;
    sws_freeContext(handle->img_convert_ctx);
    av_frame_free(&(handle->pRGBFrame));
    av_parser_close(handle->pCodecParserCtx);
    av_frame_free(&(handle->pRGBFrame));
    avcodec_close(handle->pCodecCtx);
    av_free(handle->pCodecCtx);
    free(handle);
}

JNIEXPORT jint JNICALL Java_com_zhoulee_h264decoder_MainActivity_ReleaseH264Decoder(JNIEnv *env, jobject obj,
        jint handle)
{

}

typedef enum
{
    DecFailed = 0, DecSuccess = 1, DecNeedMoreData = 2,
} DECODERESULT;

DECODERESULT DecodeOneFrame(int decodeHandle)
{
    H264DecodeHandler* handle = (H264DecodeHandler*) decodeHandle;

    int parse_len = av_parser_parse2(handle->pCodecParserCtx, handle->pCodecCtx, &(handle->packet.data),
            &(handle->packet.size), handle->cur_ptr, handle->cur_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

    LOGD("current size is [%d], parse size is [%d], handle->packet.size [%d]",
            handle->cur_size, parse_len, handle->packet.size);

    handle->cur_ptr += parse_len;
    handle->cur_size -= parse_len;

    if (0 == handle->packet.size)
    {
        LOGD("handle->packet.size is 0, need read more data");
        return DecNeedMoreData;
    }

    int decode_ret = avcodec_decode_video2(handle->pCodecCtx, handle->pFrame, &(handle->got_picture),
            &(handle->packet));

    if (decode_ret < 0)
    {
        LOGE("avcodec_decode_video2 failed");
        return DecFailed;
    }

    if (handle->got_picture)
    {
        if (handle->first_time)
        {
            LOGD("CodecCtx->codec->long_name [%s]", handle->pCodecCtx->codec->long_name);
            LOGD("CodecCtx->width [%d], CodecCtx->height [%d]", handle->pCodecCtx->width, handle->pCodecCtx->height);

            handle->img_convert_ctx = sws_getContext(handle->pCodecCtx->width, handle->pCodecCtx->height,
                    handle->pCodecCtx->pix_fmt, handle->pCodecCtx->width, handle->pCodecCtx->height, TARGET_VIDEO_TYPE,
                    SWS_BICUBIC, NULL, NULL, NULL);

            handle->pRGBFrame = av_frame_alloc();

            handle->out_buffer = (uint8_t *) av_malloc(
                    avpicture_get_size(TARGET_VIDEO_TYPE, handle->pCodecCtx->width, handle->pCodecCtx->height));

            avpicture_fill((AVPicture *) handle->pRGBFrame, handle->out_buffer, TARGET_VIDEO_TYPE,
                    handle->pCodecCtx->width, handle->pCodecCtx->height);

            handle->first_time = 0;
        }

        sws_scale(handle->img_convert_ctx, (const uint8_t* const *) handle->pFrame->data, handle->pFrame->linesize, 0,
                handle->pCodecCtx->height, handle->pRGBFrame->data, handle->pRGBFrame->linesize);
    }

    return DecSuccess;
}

DECODERESULT DecodeH264ToRGB(int decodeHandle, uint8_t* in_buffer, int in_len, uint8_t** out_buffer, int* out_len)
{
    H264DecodeHandler* handle = (H264DecodeHandler*) decodeHandle;

    if(handle->cur_size == 0)
    {
        handle->cur_ptr = in_buffer;
        handle->cur_size = in_len;
    }

    DECODERESULT decode_result = DecodeOneFrame((int) handle);

    if (DecSuccess == decode_result)
    {
        *out_buffer = handle->pRGBFrame->data[0];
        *out_len = handle->pCodecCtx->width * handle->pCodecCtx->height * handle->dst_bpp;
    }

    return decode_result;
}

C_BOOL __DecodeH264Video(FILE* fp_in, FILE* fp_out)
{
    H264DecodeHandler* handle = (H264DecodeHandler*) InitH264Decoder();
    if (handle == NULL)
    {
        LOGE("init h264 decoder failed");
        return FALSE;
    }

    uint8_t in_buffer[IN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
    memset(in_buffer, 0, sizeof(in_buffer));

    C_BOOL need_read_from_file = TRUE;
    int read_size = 0;
    int frame_index = 0;
    uint8_t* out_buffer = NULL;
    int out_len = 0;
    while (TRUE)
    {
        if (need_read_from_file == TRUE)
        {
            if ((read_size = fread(in_buffer, 1, IN_BUFFER_SIZE, fp_in)) == 0)
            {
                LOGD("read all data from file, end!!!");
                break;
            }
            LOGD("read from file size is [%d]", read_size);
        }

        DECODERESULT decode_result = DecodeH264ToRGB((int) handle, in_buffer, read_size, &out_buffer, &out_len);

        if (DecFailed == decode_result)
        {
            LOGE("decode one frame failed");
            break;
        }

        if (DecSuccess == decode_result)
        {
            fwrite(out_buffer, 1, out_len, fp_out);
            ++frame_index;
            LOGD("succeed to decode one frame, frame index [%d]", frame_index);
        }

        if (DecNeedMoreData == decode_result)
        {
            need_read_from_file = TRUE;
        }
        else
        {
            need_read_from_file = FALSE;
        }
    }

    ReleaseH264Decoder((int) handle);

    return TRUE;
}
原文地址:https://www.cnblogs.com/zhouLee/p/5148488.html