实时监控视频转码处理

实时监控视频的码率通常在5M以上,如果做比方手机端的实时预览查看,对带宽是很大的考验,所以很有必要先做降分辨率,然后降码率的处理。所有的处理在后台服务器进行,大致的业务流程如下:

海康监控摄像头输出的分辨率是:2560*1440 ,ffmpeg提供的方法能很好的完成这个流程,其实网上有很多例子,但都不全,去看ffmpeg源码提供的例子来实现是很好的办法,比方ffmpeg-4.1的例子代码在\ffmpeg-4.1\doc\examples,参考封装了一个类来做解码、缩放和编码的流程,代码如下图:




/* 
created:2019/04/02
*/
#ifndef RTP_RESAMPLE_TASK_H__
#define RTP_RESAMPLE_TASK_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" {
#include <libavcodec/avcodec.h>  
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/base64.h>

#include <libavutil/imgutils.h>
#include <libavutil/parseutils.h>
#include <libswscale/swscale.h>

}

#include <stdio.h>
  
#include "Task.h"
#include "TimeoutTask.h"

#include "SVector.h"
 

typedef void(*EncodedCallbackFunc)(void*, char *, int);
 
typedef struct RtpData
{
    char *data;
    int length;    
}RtpData;

typedef struct DstVideoInfo
{
    int width;
    int height;
    int samplerate;
}DstVideoInfo;

typedef struct SourceVideoInfo{
    int payload_type;
    char *codec_type;
    int freq_hz;//90000

	char *sps;
	char *pps;
    long profile_level_id;
    char *media_header;
}SourceVideoInfo;


typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *context;// Codec Context
    AVCodecParserContext *parser;
    struct AVFrame *frame;// Frame 
    AVPacket *pkt;
 
    int frame_count;
    int iWidth;
    int iHeight;
    int comsumedSize; 
    int skipped_frame;

    //for decodec
    void* accumulator;
    int accumulator_pos;
    int accumulator_size;

    char *szSourceDecodedSPS;
    int sps_len;
    char *szSourceDecodedPPS;
    int pps_len;
} X264_Decoder_Handler;

typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *context;// Codec Context
    int frame_count;
    struct AVFrame *frame;// Frame  
    AVPacket *pkt;
 
    Bool16 force_idr;
    int quality; // [1-31]

    int iWidth;
    int iHeight;
    int comsumedSize;
    int got_picture;

    char *encodedBuffer;
    int encodedBufferSize;
    int encodedSize;

    char *rawBuffer;
    int rawBufferSize;

    struct SwsContext *sws_ctx;

    char *sps;
    int sps_len;
    char *pps;
    int pps_len;

    FILE *fTest;
} X264_Encoder_Handler;

class RTPResampleTask {

public:
    //output width, heigh, samplerate
    RTPResampleTask(const DstVideoInfo *dstVideoInfo, const SourceVideoInfo *sourceVideoInfo, EncodedCallbackFunc func, void *funcArgs);
    ~RTPResampleTask();
 

    int resample(const char *inputBuffer, int inputSize, char **outputBuffer, int *outputSize);
    char *getResampleSPS(int *sps_len){
        *sps_len = encoderHandler.sps_len;
        return encoderHandler.sps;
    };
    char *getResamplePPS(int *pps_len){
        *pps_len = encoderHandler.pps_len;
        return encoderHandler.pps;
    };
    enum{
        STATE_INIT = -1,
        STATE_RUNNING = 0,
        STATE_WAITING = 1,
        STATE_START_DECODE = 2,
        STATE_DONE = 3
    };
private:
    int initEncoder();
    int initDecoder();

    void deInitEncoder();
    void deInitDecoder();

    int decodePacket(const char *inputBuffer, int inputSize);
    int encodePacket();
private:
    UInt32          fState;
    UInt32          kIdleTime;

    EncodedCallbackFunc callback;
    SVector<RtpData *> reEncodedWaitList;

    SourceVideoInfo sourceVideoInfo;
    DstVideoInfo dstVideoInfo;
 
    X264_Decoder_Handler decoderHandler;
    X264_Encoder_Handler encoderHandler;

    void *funcArgs;
};


#endif//RTP_RESAMPLE_TASK_H__


/* 
created:2019/04/02
*/

#include "RTPResampleTask.h"


#define INBUF_SIZE 4096
#define H264_RTP_PAYLOAD_SIZE	1320


RTPResampleTask::RTPResampleTask(const DstVideoInfo *dstVideoInfo, const SourceVideoInfo *sourceVideoInfo, EncodedCallbackFunc func , void *funcArgs){
    uint8_t szDecodedSPS[128] = { 0 };
    this->decoderHandler.sps_len = av_base64_decode((uint8_t*)szDecodedSPS, (const char *)sourceVideoInfo->sps, sizeof(szDecodedSPS));//nSPSLen=24
    this->decoderHandler.szSourceDecodedSPS = (char *)malloc(this->decoderHandler.sps_len);
	if (this->decoderHandler.szSourceDecodedSPS != NULL){
		memcpy(this->decoderHandler.szSourceDecodedSPS, szDecodedSPS, this->decoderHandler.sps_len);
	}

    uint8_t szDecodedPPS[128] = { 0 };
    this->decoderHandler.pps_len = av_base64_decode(( uint8_t*)szDecodedPPS, (const char *)sourceVideoInfo->pps, sizeof(szDecodedPPS));//nPPSLen=4
    this->decoderHandler.szSourceDecodedPPS = (char *)malloc(this->decoderHandler.pps_len);
	if (this->decoderHandler.szSourceDecodedPPS != NULL){
		memcpy(this->decoderHandler.szSourceDecodedPPS, szDecodedPPS, this->decoderHandler.pps_len);
	}

	this->funcArgs = funcArgs;

    kIdleTime = 100;
    fState = STATE_INIT;

    initEncoder();
    initDecoder();
}

RTPResampleTask::~RTPResampleTask(){

    deInitEncoder();
    deInitDecoder();
}

int RTPResampleTask::initEncoder(){
    AVCodecID codec_id = AV_CODEC_ID_H264;
    
    if (codec_id == AV_CODEC_ID_H264){

    }
    encoderHandler.rawBuffer= NULL;
    encoderHandler.rawBufferSize = 0;
    encoderHandler.encodedBuffer= NULL;
    encoderHandler.encodedBufferSize = 0;
    encoderHandler.sws_ctx = NULL;

    encoderHandler.pkt = av_packet_alloc();
    if (!encoderHandler.pkt) { 
        printf("encoderHandler.pkt == NULL");
        return -1;
    }
    encoderHandler.codec = avcodec_find_encoder(codec_id); //AV_CODEC_ID_AAC;
    if(encoderHandler.codec == NULL ) {
        printf("encoderHandler.codec == NULL");
        return -1;
    } 
    //创建AVFormatContext结构体
    //分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行  
    encoderHandler.context = avcodec_alloc_context3(encoderHandler.codec); 
    if(encoderHandler.context == NULL ) {
        printf("encoderHandler.context == NULL");
        return -1;
    } 
    //设置AVCodecContext编码参数
    struct AVCodecContext *c      = encoderHandler.context;
    avcodec_get_context_defaults3(c, encoderHandler.codec);
    c->codec_id  = codec_id; 
    c->bit_rate = 500000;
    c->time_base.den = 25; //分母
    c->time_base.num = 1;  //分子
    /* resolution must be a multiple of two */
    c->width = 640;
    c->height = 480;
    /* frames per second */
    c->time_base = (AVRational){1, 25};
    c->framerate = (AVRational){25, 1};
    c->gop_size = 1;//
    c->max_b_frames = 0;
	//c->rtp_payload_size = H264_RTP_PAYLOAD_SIZE;
    c->pix_fmt = AV_PIX_FMT_YUV420P;
    c->codec_type = AVMEDIA_TYPE_VIDEO; 
    //c->flags|= CODEC_FLAG_GLOBAL_HEADER; 
    //AVOptions的参数
    av_opt_set(c->priv_data, "preset", "slow", 0);
    av_opt_set(c->priv_data, "preset", "ultrafast", 0);
    av_opt_set(c->priv_data, "tune","stillimage,fastdecode,zerolatency",0);
    av_opt_set(c->priv_data, "x264opts","crf=26:vbv-maxrate=728:vbv-bufsize=364:keyint=25",0); 

    encoderHandler.frame = av_frame_alloc();
    if(encoderHandler.frame == NULL )  {
        printf("encoderHandler.frame == NULL");
        return -1;
    } 
    encoderHandler.frame->format = c->pix_fmt;
    encoderHandler.frame->width  = c->width;
    encoderHandler.frame->height = c->height;

 
    avpicture_alloc((AVPicture *)encoderHandler.frame,AV_PIX_FMT_YUV420P, encoderHandler.frame->width, encoderHandler.frame->height);  //desW,desH分别为目标分辨率的宽度、高度

    /* open it */
    int ret = avcodec_open2(encoderHandler.context, encoderHandler.codec , NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open codec: %d\n", ret);
        return -1;
    }

    encoderHandler.fTest  = fopen("/tmp/test_out.h264", "wb");
    if (!encoderHandler.fTest) {
        fprintf(stderr, "Could not open /tmp/test_out.h264 \n");
        return -1;
    }

    encoderHandler.sps = NULL;
    encoderHandler.sps_len = 0;
    encoderHandler.pps = NULL;
    encoderHandler.pps_len = 0;

	return 0;
}

void RTPResampleTask::deInitEncoder(){ 
    if(encoderHandler.context){ 
        avcodec_free_context(&encoderHandler.context);
        encoderHandler.context = NULL;
    }
    if(encoderHandler.frame){
        av_frame_free(&encoderHandler.frame);
        encoderHandler.frame = NULL;
    }
    if (encoderHandler.pkt){
        av_packet_free(&encoderHandler.pkt);
        encoderHandler.pkt = NULL;
    }
    if (encoderHandler.sws_ctx){
        sws_freeContext(encoderHandler.sws_ctx);
        encoderHandler.sws_ctx = NULL;
    }
    if (encoderHandler.fTest){
        fclose(encoderHandler.fTest);
    }
    if (encoderHandler.sps != NULL){
        free(encoderHandler.sps);
    }
    if (encoderHandler.pps != NULL){
        free(encoderHandler.pps);
    }
}


int RTPResampleTask::initDecoder(){
    AVCodecID codec_id = AV_CODEC_ID_H264;
    
    if (codec_id == AV_CODEC_ID_H264){

    }
    decoderHandler.pkt = av_packet_alloc();
    if (!decoderHandler.pkt) { 
        printf("decoderHandler.pkt == NULL");
        return -1;
    }

    decoderHandler.codec = avcodec_find_decoder(codec_id); //AV_CODEC_ID_AAC;
    if(decoderHandler.codec == NULL )
    {
        printf("decoderHandler.codec == NULL");
        return -1;
    } 
    decoderHandler.parser = av_parser_init(decoderHandler.codec->id);
    if (!decoderHandler.parser) { 
        printf("decoderHandler.parser == NULL");
        return -1;
    }
    //创建AVFormatContext结构体
    //分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行  
    decoderHandler.context = avcodec_alloc_context3(decoderHandler.codec); 
    if (!decoderHandler.context) { 
        printf("decoderHandler.context == NULL");
        return -1;
    }

    int sps_pps_len = decoderHandler.sps_len + decoderHandler.pps_len + 6;
    unsigned char *szSPSPPS = (unsigned char *)av_mallocz(sps_pps_len + 1);
    char spsHeader[4] = {0x00, 0x00,0x00,  0x01};
    char ppsHeader[3] = {0x00, 0x00, 0x01};
    memcpy(szSPSPPS, spsHeader, sizeof(spsHeader));
    memcpy(szSPSPPS + sizeof(spsHeader), decoderHandler.szSourceDecodedSPS, decoderHandler.sps_len);
    memcpy((void *)(szSPSPPS + sizeof(spsHeader)  + decoderHandler.sps_len), ppsHeader, sizeof(ppsHeader));
    memcpy((void *)(szSPSPPS + sizeof(spsHeader)  + sizeof(ppsHeader) + decoderHandler.sps_len), decoderHandler.szSourceDecodedPPS, decoderHandler.pps_len);

    decoderHandler.context->extradata_size = sps_pps_len;
    decoderHandler.context->extradata = (uint8_t*)av_mallocz(decoderHandler.context->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
    memcpy(decoderHandler.context->extradata, szSPSPPS, sps_pps_len);

    decoderHandler.context->time_base.num = 1;
    decoderHandler.context->time_base.den = 25;
    if (avcodec_open2(decoderHandler.context, decoderHandler.codec, NULL) < 0) {
           
        printf("avcodec_open2 return failed");
        return -1;
    }
    decoderHandler.frame = av_frame_alloc();
    if (!decoderHandler.frame) { 
        printf("decoderHandler.frame is null.");
        return -1;
    }
        
    printf("initDecoder, width:%d, height:%d", decoderHandler.context->width, decoderHandler.context->height);
    return 0;
}

void RTPResampleTask::deInitDecoder(){
    if(decoderHandler.frame){
        av_frame_free(&decoderHandler.frame);
        decoderHandler.frame = NULL;
    }    
    if(decoderHandler.parser){
        av_parser_close(decoderHandler.parser);
        decoderHandler.parser = NULL;
    }
    if (decoderHandler.pkt){
        av_packet_free(&decoderHandler.pkt);
    }
    if (decoderHandler.context->extradata != NULL){
        av_free(decoderHandler.context->extradata);
    }
    if(decoderHandler.context){
        avcodec_free_context(&decoderHandler.context); 
        decoderHandler.context = NULL;
    }

}  
 

int RTPResampleTask::resample(const char *inputBuffer, int inputSize, char **outputBuffer, int *outputSize){
    *outputBuffer = NULL;
    *outputSize = 0;
    int ret = decodePacket((const char *)inputBuffer, inputSize);
    //printf("video resample decodePacket ret:%d outputSize:%d\n", ret, encoderHandler.rawBufferSize);
    if (ret == 0){
        char *encodeOutputBuffer = NULL;
        int encodeOutputSize = 0;
        int src_linesize[4], dst_linesize[4];

        //scale
        if (encoderHandler.sws_ctx == NULL){
            encoderHandler.sws_ctx = sws_getContext(decoderHandler.context->width, decoderHandler.context->height, decoderHandler.context->pix_fmt,
                             encoderHandler.context->width, encoderHandler.context->height, AV_PIX_FMT_YUV420P,
                             SWS_BILINEAR, NULL, NULL, NULL);
        }
        sws_scale(encoderHandler.sws_ctx,  decoderHandler.frame->data,
                  decoderHandler.frame->linesize, 0, decoderHandler.context->height, encoderHandler.frame->data, encoderHandler.frame->linesize);

        ret = encodePacket();
        if (ret != 0){
            printf("video resample ret:%d err\n", ret);
            return -1;
        } 
        fwrite(encoderHandler.encodedBuffer, 1, encoderHandler.encodedSize, encoderHandler.fTest);
        *outputBuffer = encoderHandler.encodedBuffer;
        *outputSize = encoderHandler.encodedSize;
        int typeIndex = 3;//default 00 00 01 
        if (encoderHandler.encodedBuffer[3] == 0x01){
            typeIndex = 4;
        }
        
        if (encoderHandler.encodedBuffer[typeIndex] == 0x67  && encoderHandler.sps == NULL){
            printf("video resample has sps:%d  \n", encoderHandler.encodedSize);  
            encoderHandler.sps_len = 0;
            int i = 0;
            unsigned short find_sps_flag = 0;
            while(i++ < encoderHandler.encodedSize){
                if ((encoderHandler.encodedBuffer[typeIndex] == 0x00 &&
                encoderHandler.encodedBuffer[typeIndex + 1] == 0x00 && 
                encoderHandler.encodedBuffer[typeIndex + 2] == 0x01 && 
                encoderHandler.encodedBuffer[typeIndex + 3] == 0x68)
                ){
                    find_sps_flag = 1;
                    break;
                }
                typeIndex++;
            }      
            if (!find_sps_flag){
                return 0;    
            }
            find_sps_flag = 0;

            encoderHandler.sps_len = typeIndex;
            printf("video resample encoderHandler.sps_len:%d  \n", encoderHandler.sps_len);  
            
            encoderHandler.sps = (char *)malloc(encoderHandler.sps_len);
            if (encoderHandler.sps != NULL){
                memcpy((void *)encoderHandler.sps, (void *)encoderHandler.encodedBuffer, encoderHandler.sps_len);
            }
            encoderHandler.pps_len = 0;
            typeIndex = encoderHandler.sps_len + 4;
            while(i++ < encoderHandler.encodedSize){
                if (
                    (encoderHandler.encodedBuffer[typeIndex] == 0x00 &&
                    encoderHandler.encodedBuffer[typeIndex +1] == 0x00 &&  
                    encoderHandler.encodedBuffer[typeIndex +2] == 0x01)
                ){
                    find_sps_flag = 1;
                    break;
                }
                typeIndex++;
                encoderHandler.pps_len++;
            }     
            if (!find_sps_flag){
                return 0;    
            }
            encoderHandler.pps_len += 4;

            printf("video resample encoderHandler.pps_len:%d  \n", encoderHandler.pps_len);   
            encoderHandler.pps = (char *)malloc(encoderHandler.pps_len);
            if (encoderHandler.pps != NULL){
                memcpy((void *)encoderHandler.pps, &encoderHandler.encodedBuffer[encoderHandler.sps_len], encoderHandler.pps_len);
            } 
        }
        return 0;  
    } 
        
    return -1; 
}

int RTPResampleTask::decodePacket(const char *inputBuffer, int inputSize){
 
    int ret;  
    uint8_t *data = ( uint8_t *)inputBuffer;
    int data_size = inputSize;
    //while (data_size > 0) 
    { 
        encoderHandler.rawBufferSize =   0;
        av_init_packet(decoderHandler.pkt);
        decoderHandler.pkt->dts  = AV_NOPTS_VALUE;
        decoderHandler.pkt->size = (int)inputSize;
        decoderHandler.pkt->data = (uint8_t *)inputBuffer;  
        if (decoderHandler.pkt->size){
		    ret = avcodec_send_packet(decoderHandler.context, decoderHandler.pkt);
		    if (ret < 0) {
		        fprintf(stderr, "decodePacket Error sending a packet for decoding\n");
		        return -1;
		    }
 
	        ret = avcodec_receive_frame(decoderHandler.context, decoderHandler.frame);
	        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){  
	            return -1;
	        }
	        else if (ret < 0) {
	            fprintf(stderr, "decodePacket Error during decoding :%d\n", ret);
	            return -1;
	        } 
	    	int xsize = avpicture_get_size(decoderHandler.context->pix_fmt, decoderHandler.context->width, decoderHandler.context->height);	
            //fprintf(stderr, "decodePacket end decoding :%d, width:%d, height:%d\n", xsize, decoderHandler.context->width, decoderHandler.context->height);
            encoderHandler.rawBufferSize = xsize;
            //
        }else{ 
        	return -1;
        }
    }
 
	return 0;
}

int RTPResampleTask::encodePacket(){
    #if 0
    int size = avpicture_fill((AVPicture*)encoderHandler.frame, (uint8_t*)inputBuffer, AV_PIX_FMT_YUV420P, encoderHandler.context->width, encoderHandler.context->height);
    if (size != inputSize){
        /* guard */
        printf("RTPResampleTask::encodePacket invalid size: %u<>%u", size, inputSize);
        return 0;
    }
    #endif//encoderHandler.frame
    int ret = avcodec_send_frame(encoderHandler.context, encoderHandler.frame);
    if (ret < 0) {
        printf("RTPResampleTask::encodePacket error sending a frame for encoding, ret:%d\n", ret);
        return ret;
    }

    encoderHandler.encodedSize = 0;

    while (ret >= 0) 
    {
        ret = avcodec_receive_packet(encoderHandler.context, encoderHandler.pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){ 
            if (encoderHandler.encodedSize > 0){
                return 0;
            }
            return -1;
        } else if (ret < 0) {
            printf("RTPResampleTask::encodePacket error during encoding\n");
            return ret;
        }
        if (encoderHandler.encodedBuffer == NULL){ 
            encoderHandler.encodedBuffer = (char *)malloc((encoderHandler.context->width*encoderHandler.context->height * 3)/2);   
            encoderHandler.encodedBufferSize = (encoderHandler.context->width*encoderHandler.context->height * 3)/2;
        }

        if (encoderHandler.encodedBufferSize < (encoderHandler.pkt->size + encoderHandler.encodedSize)){ 
            encoderHandler.encodedBuffer = (char *)realloc(encoderHandler.encodedBuffer, encoderHandler.pkt->size + encoderHandler.encodedSize); 
            encoderHandler.encodedBufferSize += encoderHandler.pkt->size + encoderHandler.encodedSize;
        }
    	if (encoderHandler.encodedBuffer){
    		memcpy((void *)(encoderHandler.encodedBuffer + encoderHandler.encodedSize), encoderHandler.pkt->data, encoderHandler.pkt->size);
    	}
        encoderHandler.encodedSize += encoderHandler.pkt->size;
        //printf("RTPResampleTask::encodePacket success ret:%d\n", encoderHandler.pkt->size); 
        //if (callback != NULL){
            //callback(funcArgs, (char*)encoderHandler.pkt->data, encoderHandler.pkt->size);
        //}
        av_packet_unref(encoderHandler.pkt);
    }
    //printf("RTPResampleTask::encodePacket success ret:%d\n", encoderHandler.encodedBufferSize); 
	return 0;
}
 

C语言版本:


#include <stdio.h>
#include <stdlib.h> 
#include <fcntl.h>
#include <unistd.h> 
#include <netinet/in.h> 

#include <fcntl.h>
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/base64.h"

#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libswscale/swscale.h"


 

typedef void(*EncodedCallbackFunc)(void*, char *, int);
 
typedef struct _RtpData
{
    char *data;
    int length;    
}RtpData;

typedef struct _DstVideoInfo
{
    int width;
    int height;
    int samplerate;
}DstVideoInfo;

typedef struct _SourceVideoInfo{
    int payload_type;
    char *codec_type;
    int freq_hz;//90000

	char *sps;
	char *pps;
    long profile_level_id;
    char *media_header;
}SourceVideoInfo;


typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *context;// Codec Context
    AVCodecParserContext *parser;
    struct AVFrame *frame;// Frame 
    AVPacket *pkt;
 
    int frame_count;
    int iWidth;
    int iHeight;
    int comsumedSize; 
    int skipped_frame;

    //for decodec
    void* accumulator;
    int accumulator_pos;
    int accumulator_size;

    char *szSourceDecodedSPS;
    int sps_len;
    char *szSourceDecodedPPS;
    int pps_len;
} X264_Decoder_Handler;

typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *context;// Codec Context
    int frame_count;
    struct AVFrame *frame;// Frame  
    AVPacket *pkt;
 
    gboolean force_idr;
    int quality; // [1-31]

    int iWidth;
    int iHeight;
    int comsumedSize;
    int got_picture;

    char *encodedBuffer;
    int encodedBufferSize;
    int encodedSize;

    char *rawBuffer;
    int rawBufferSize;

    struct SwsContext *sws_ctx;

    char *sps;
    int sps_len;
    char *pps;
    int pps_len;

    FILE *fTest;
} X264_Encoder_Handler;

//output width, heigh, samplerate
typedef struct _RTPResampleTask {
 
    guint32          fState; 

    EncodedCallbackFunc callback; 
    void *funcArgs;

    SourceVideoInfo sourceVideoInfo;
    DstVideoInfo dstVideoInfo;
 
    X264_Decoder_Handler decoderHandler;
    X264_Encoder_Handler encoderHandler;

}RTPResampleTask;


void initRTPResampleTask(RTPResampleTask *this, const DstVideoInfo *dstVideoInfo, const SourceVideoInfo *sourceVideoInfo, EncodedCallbackFunc func, void *funcArgs);
void deInitRTPResampleTask(RTPResampleTask *this); 
int resample(RTPResampleTask *this, const char *inputBuffer, int inputSize, char **outputBuffer, int *outputSize);

char *getResampleSPS(RTPResampleTask *this, int *sps_len){
    *sps_len = this->encoderHandler.sps_len;
    return this->encoderHandler.sps;
};
char *getResamplePPS(RTPResampleTask *this, int *pps_len){
    *pps_len = this->encoderHandler.pps_len;
    return this->encoderHandler.pps;
};
#define RTP_VERSION_ 2  
#define BUF_SIZE (1024 * 1024* 4)  

#define AUDIO_BUF_SIZE 1024*2


typedef struct   
{  
    //LITTLE_ENDIAN  
    unsigned short   cc:4;      /* CSRC count                 */  
    unsigned short   x:1;       /* header extension flag      */  
    unsigned short   p:1;       /* padding flag               */  
    unsigned short   v:2;       /* packet type                */  
    unsigned short   pt:7;      /* payload type               */  
    unsigned short   m:1;       /* marker bit                 */  

    uint16_t    seq;      /* sequence number            */  
    guint32    ts;       /* timestamp                  */  
    guint32    ssrc;     /* synchronization source     */  
} rtp_hdr_t; 

typedef struct CH264_RTP_UNPACK{     
    rtp_hdr_t m_RTP_Header ;  
	char m_H264PAYLOADTYPE ;  
    char *m_pBuf ;  
  
    gboolean m_bSPSFound ;  
    gboolean m_bWaitKeyFrame ;  
    char *m_pStart ;  
    char *m_pEnd ;  
    guint32 m_dwSize;  

    guint32 m_wSeq ;    
    guint32 m_ssrc ;
	
	uint8_t* m_pSPS;
	uint8_t* m_pPPS;
	uint16_t m_iSPSLen;
	uint16_t m_iPPSLen;
}CH264_RTP_UNPACK;  
 

typedef struct CAAC_RTP_UNPACK { 
 
	rtp_hdr_t m_RTP_Header ;
	char *m_pBuf;

	int g_fd;
	guint32 m_iSeq ; 
	uint8_t m_pSpecificInfo[4];
}CAAC_RTP_UNPACK;


void initH264 (CH264_RTP_UNPACK *self,  unsigned char H264PAYLOADTYPE/* = 96 */); 
void deInitH264(CH264_RTP_UNPACK *self);

//pBufΪH264 RTPÊÓƵÊý¾Ý°ü£¬nSizeΪRTPÊÓƵÊý¾Ý°ü×Ö½Ú³¤¶È£¬outSizeΪÊä³öÊÓƵÊý¾ÝÖ¡×Ö½Ú³¤¶È¡£  
//·µ»ØֵΪָÏòÊÓƵÊý¾ÝÖ¡µÄÖ¸Õë¡£ÊäÈëÊý¾Ý¿ÉÄܱ»ÆÆ»µ¡£  
char* Parse_RTP_Packet_H264 (CH264_RTP_UNPACK *self,  char *pBuf, unsigned short nSize, int *outSize, guint32* timestamp);
void SetLostPacket();
    
void initAAC (CAAC_RTP_UNPACK *self,  unsigned char H264PAYLOADTYPE /*= 96*/ ); 
void deInitAAC(CAAC_RTP_UNPACK *self);
char* Parse_RTP_Packet_AAC (CAAC_RTP_UNPACK *self, char *pBuf, unsigned short nSize, int *outSize, guint32* timestamp); 
void addADTStoPacket(CAAC_RTP_UNPACK *self, uint8_t* adts, int packetLen);
void addADTStoPacket2(CAAC_RTP_UNPACK *self, uint8_t* adts_header, int frame_length);




//********************************* H264 ****/

const uint8_t start_sequence[] = { 0, 0, 0, 0x01 };
uint8_t adts[7] = {0};

// one_piece
unsigned char _sps[] = {0x67,0x64,0x00,0x1F,0xAC,0xD9,0x40,0xD4,0x3D,0xA1,0x00,0x01,0x00,0x00,0x03,0x00,0x34,0xD9,0x96,0x0F,0x18,0x31,0x96}; //23
unsigned char _pps[] = {0x68,0xEB,0xE3,0xCB,0x22,0xC0}; // 6

void initH264 (CH264_RTP_UNPACK *this,  unsigned char H264PAYLOADTYPE/* = 96 */) 
{  
	memset(this, 0, sizeof(CAAC_RTP_UNPACK));
	this->m_pBuf = (char *)malloc(BUF_SIZE);  
	if ( this->m_pBuf == NULL ){  
		return ;  
	}  
	memset(this->m_pBuf, 0, BUF_SIZE);
	this->m_H264PAYLOADTYPE = H264PAYLOADTYPE ;  
	this->m_pEnd = this->m_pBuf + BUF_SIZE ;  
	this->m_pStart = this->m_pBuf ;  
	this->m_dwSize = 0 ; 
	this->m_iSPSLen = 0;
	this->m_iPPSLen = 0;
}  
  
void deInitH264(CH264_RTP_UNPACK *this) 
{  
	free(this->m_pBuf);
	if(this->m_pSPS) free(this->m_pSPS);
	if(this->m_pPPS) free(this->m_pPPS);
 
}  
   
char* Parse_RTP_Packet (CH264_RTP_UNPACK *this, char *pBuf, unsigned short nSize, int *outSize,  guint32* timestamp)  
{  
	if ( nSize <= 12 )  {  
		return NULL ;  
	}  

	char *head = (char*)&this->m_RTP_Header ;  
	head[0] = pBuf[0] ;  // v:2 p:1 x:1 cc:4
	head[1] = pBuf[1] ;  // m:1 PT:7


	// ntohs
	this->m_RTP_Header.seq = ntohs(*((uint16_t*)(pBuf+2))); // 2Byte 
	this->m_RTP_Header.ts = ntohl(*((guint32*)(pBuf+4))); // 4Byte
	// this->m_RTP_Header.ssrc = ntohl(*((guint32*)(pBuf+8)));     // 4Byte
	// printf(" this->m_RTP_Header.ts: %ld\n", this->m_RTP_Header.ts);
	char *pPayload = pBuf + 12 ;  
	int16_t payloadSize = nSize - 12;
    
    unsigned char padding = ((head[0] & 0x20) >> 5);
	unsigned int paddinglength = 0;
    if (padding & 0x1){
		paddinglength = *(uint8_t*)(pBuf+(nSize -1));
		//printf("Packet has padding Flg, seq:%d, padd:%d\n", this->m_RTP_Header.seq, paddinglength);
		payloadSize -= paddinglength;
	}

    if (payloadSize <= 0){
    	return NULL;
    }

	int PayloadType = pPayload[0] & 0x1f ;  // type : end 5 
	int NALType = PayloadType ;
	// printf("NALType =%d, seq0=%d\n", NALType, this->m_RTP_Header.seq); 
	
   	char spsHeader[4] = {0x00, 0x00, 0x00, 0x01};
    char ppsHeader[3] = {0x00, 0x00, 0x01};
	if ( (NALType == 0x07 || NALType == 0x08) && !this->m_bSPSFound ) // SPS PPS  
	{  
		this->m_wSeq = this->m_RTP_Header.seq ;  
		if ( NALType == 0x07 ){  // SPS  
			this->m_pSPS = (uint8_t*)malloc(payloadSize +  sizeof(spsHeader));

			memcpy(this->m_pSPS, spsHeader, sizeof(spsHeader));
			memcpy(this->m_pSPS + sizeof(spsHeader), pPayload, payloadSize);
			this->m_iSPSLen = payloadSize + sizeof(spsHeader);
			printf("Get SPS(nal_type=0x07)\n");
			

		  	memset(this->m_pStart, 0, BUF_SIZE);
			this->m_pBuf =  this->m_pStart; 
			memcpy(this->m_pBuf, this->m_pSPS, this->m_iSPSLen);
			*outSize = this->m_iSPSLen;
			*timestamp = this->m_RTP_Header.ts;
			return this->m_pStart;   
		} else{
			this->m_pPPS = (uint8_t*)malloc(payloadSize + sizeof(ppsHeader));
			memcpy(this->m_pSPS, ppsHeader, sizeof(ppsHeader));
			memcpy(this->m_pPPS + sizeof(ppsHeader), pPayload, payloadSize);
			this->m_iPPSLen = payloadSize + sizeof(ppsHeader);
			this->m_bSPSFound = TRUE ; 
			printf("Get PPS(nal_type=0x08)\n"); 

		  	memset(this->m_pStart, 0, BUF_SIZE);
			this->m_pBuf =  this->m_pStart;
			memcpy(this->m_pBuf, this->m_pSPS, this->m_iSPSLen);
			*outSize = this->m_iPPSLen;
			*timestamp = this->m_RTP_Header.ts;
			return this->m_pStart;   
		} 
	}
		
	if ( !this->m_bSPSFound ){ 
		printf("this->m_bSPSFound=%d, NALType=%d\n", this->m_bSPSFound, NALType);
#if 1 // one_piece
		this->m_iSPSLen = sizeof(_sps)/sizeof(_sps[0]);
		this->m_pSPS = (uint8_t*)malloc(this->m_iSPSLen);
		memcpy(this->m_pSPS, _sps, this->m_iSPSLen);

		this->m_iPPSLen = sizeof(_pps)/sizeof(_pps[0]);
		this->m_pPPS = (uint8_t*)malloc(this->m_iPPSLen);
		memcpy(this->m_pPPS, _pps, this->m_iPPSLen);

		this->m_bSPSFound = TRUE;
#endif
		return NULL ;  
	}  

///////////////////////////////////////////////////////////////  
	/*if (NALType >= 1 && NALType <= 23)
        NALType = 1;
	*/
	if(NALType >= 28){ // FU_A  
		if ( payloadSize < 2 ){  
			return NULL ;  
		}
		 // ffmpeg rtpdec_h264.c
		// fu_indicator fu_header [2 Byte]
		uint8_t nal = 0;
		uint8_t fu_indicator = pPayload[0];
		uint8_t fu_header    = pPayload[1];
		uint8_t start_bit = fu_header >> 7; //= *(pPayload + 1) & 0x80;
		uint8_t end_bit = fu_header & 0x40 ; //*(pPayload + 1) & 0x40;
		NALType = fu_header & 0x1f; //*(pPayload+1) & 0x1f ;
		if(NALType == 5){
			nal = (fu_indicator & 0xe0 )| NALType;
		}			 
	    else{
			nal = (fu_indicator & 0x40 )| NALType;
		}			
			 			
		// printf("NALType =%d, end_bit=%d, seq=%d\n", NALType, end_bit, this->m_RTP_Header.seq); 		
		// skip the fu_indicator and fu_header
		pPayload += 2;
		payloadSize -= 2;
		if(start_bit){
			//printf("start_bit =1,  NALType =%d, seq=%d\n", NALType, this->m_RTP_Header.seq);
			memset(this->m_pStart, 0, BUF_SIZE);
			this->m_pBuf =  this->m_pStart;
			if (NALType == 0x07){

				memcpy(this->m_pBuf, spsHeader, sizeof(spsHeader));
				this->m_dwSize = sizeof(ppsHeader);
			} else if (NALType == 0x08) {

			    memcpy(this->m_pBuf, ppsHeader, sizeof(ppsHeader));
				this->m_dwSize = sizeof(ppsHeader);
			} else {
				memcpy(this->m_pBuf, start_sequence, sizeof(start_sequence)); 
				memcpy(this->m_pBuf+sizeof(start_sequence), &nal, 1); 
				this->m_dwSize = sizeof(start_sequence) + 1;
			}				
		}
		memcpy(this->m_pBuf + this->m_dwSize, pPayload, payloadSize);			
		// printf("NALType =%d, seq=%d, payloadSize=%d, this->m_dwSize=%d\n", NALType, this->m_RTP_Header.seq, payloadSize,  this->m_dwSize); 	
		this->m_dwSize += payloadSize ; 
		if(this->m_RTP_Header.m){
			//printf("this->m_dwSize=%d, end_bit =%d, NALType =%d, seq=%d\n", this->m_dwSize, end_bit, NALType, this->m_RTP_Header.seq); 
			*outSize = this->m_dwSize;
			*timestamp = this->m_RTP_Header.ts;
			return this->m_pStart;
		}
		return NULL;
	}else{
		memset(this->m_pStart, 0, BUF_SIZE);
		this->m_pBuf =  this->m_pStart;
		memcpy(this->m_pBuf, start_sequence, sizeof(start_sequence));
		memcpy(this->m_pBuf + sizeof(start_sequence), pPayload, payloadSize);
		*outSize = payloadSize + sizeof(start_sequence);
		*timestamp = this->m_RTP_Header.ts;
		return this->m_pStart;
	}								
}  
  
void SetLostPacket(CH264_RTP_UNPACK *this)  
{  
	this->m_bSPSFound = FALSE;  
	this->m_bWaitKeyFrame = TRUE ;    
	this->m_pStart = this->m_pBuf ;  
	this->m_dwSize = 0 ;  
}

void initAAC(CAAC_RTP_UNPACK *this,  unsigned char H264PAYLOADTYPE)
{
	this->m_pBuf = (char *)malloc(AUDIO_BUF_SIZE);  
	if ( this->m_pBuf == NULL ){  
		return ;  
	}  
	memset(this->m_pBuf, 0, AUDIO_BUF_SIZE);
	memset(this->m_pSpecificInfo, 0 , 4);
	this->m_iSeq = 0;

	
	this->g_fd = open("/usr/local/movies/one_p.aac", O_CREAT  | O_WRONLY , 0666);
    if(this->g_fd != -1)
    {
        printf("open a aac file ok\n");
    } 
}

void deInitAAC(CAAC_RTP_UNPACK *this)
{
	if (this->m_pBuf != NULL) {
		free(this->m_pBuf);
		this->m_pBuf = NULL;
	}
	
	if(this->g_fd != -1){
        close(this->g_fd);
    }
}

char* Parse_RTP_Packet_AAC( CAAC_RTP_UNPACK *this, char *pBuf, unsigned short nSize, int *outSize,  guint32* timestamp)  
{
	if ( nSize <= 12 )  {  
		return NULL ;  
	}  

	char* payloadbuf = pBuf;
	int currentPos = 0;
	//char *head = (char*)&this->m_RTP_Header ;  
	//head[0] = pBuf[0] ;  // v:2 p:1 x:1 cc:4
	//head[1] = pBuf[1] ;  // m:1 PT:7

	// ntohs
	this->m_RTP_Header.seq = ntohs(*((uint16_t*)(pBuf+2))); // 2Byte 
	// this->m_RTP_Header.ts = ntohl(*((guint32*)(pBuf+4))); // 4Byte
	*timestamp = ntohl(*((guint32*)(pBuf+4))); // 4Byte
	// this->m_RTP_Header.ssrc = ntohl(*((guint32*)(pBuf+8)));     // 4Byte
	 printf("this->m_iSeq=%d, this->m_RTP_Header.seq: %ld, timestamp=%d\n",this->m_iSeq, this->m_RTP_Header.seq, *timestamp);  

	if(this->m_iSeq != 0 && this->m_iSeq == this->m_RTP_Header.seq)
		return NULL;
	this->m_iSeq = this->m_RTP_Header.seq;

	uint16_t us_header_len = ntohs(*((uint16_t*)(pBuf+12)));
	uint16_t us_header_plen = us_header_len >> 3;
	uint16_t us_header = ntohs(*((uint16_t*)(pBuf+14)));
	uint16_t payloadLen = us_header >> 3;
	printf("us_header_len=%d, payloadLen=%d\n",  us_header_plen, payloadLen);

	 int8_t hasv = *(pBuf+12);
	 int8_t lasv = *(pBuf+13);
	 u_int16_t au_size = ((hasv << 5) & 0xE0) | ((lasv >> 3) & 0x1f);
	 printf("Parse_RTP_Packet nSize=%d, au_size=%d\n", nSize, au_size);

	if(nSize < au_size)
		return NULL ;  			

	currentPos += 14;
	payloadbuf = (pBuf+14 + au_size);

	int required_size = 0;
    int i = 0;
	for (i = 0; i < au_size; i += 2) {
      	hasv = *(pBuf+14+i);
        lasv = *(pBuf+14+i+1);
	
        u_int16_t sample_size = ((hasv << 5) & 0xE0) | ((lasv >> 3) & 0x1f);
		// printf("Parse_RTP_Packet 1 sample_size=%d\n",  sample_size);
		currentPos +=2 ;
        // TODO: FIXME: finger out how to parse the size of sample.
        if (sample_size < 0x100 && nSize >= (required_size + sample_size + 0x100 + currentPos)) {
            sample_size = sample_size | 0x100;
        }
		printf("Parse_RTP_Packet 2 sample_size=%d\n",  sample_size);
		
        char* sample = payloadbuf + required_size;        

		if(nSize < (required_size+currentPos+sample_size)) {
            printf(" error \n");
            return NULL;
        }
   		memcpy(this->m_pBuf+ required_size , sample, sample_size);
		required_size += sample_size;		
    }

	 *outSize = required_size;
	//*outSize = (nSize - (12 + au_size));
	return this->m_pBuf;
}
 

/** 
    *  Add ADTS header at the beginning of each and every AAC packet. 
    *  This is needed as MediaCodec encoder generates a packet of raw 
    *  AAC data. 
    * 
    *  Note the packetLen must count in the ADTS header itself !!! . 
    *注æ„,这里的packetLenå‚数为raw aac Packet Len + 7; 7 bytes adts header 
**/  
void addADTStoPacket(CAAC_RTP_UNPACK *self, uint8_t* adts, int packetLen) {  
       int profile = 2;  //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;  
       int freqIdx = 4;  //44K, è§åŽé¢æ³¨é‡Šavpriv_mpeg4audio_sample_rates中44100对应的数组下标,æ¥è‡ªffmpegæºç   
       int chanCfg = 2;  //è§åŽé¢æ³¨é‡Šchannel_configuration,SteroåŒå£°é“立体声  
  
       /*int avpriv_mpeg4audio_sample_rates[] = { 
           96000, 88200, 64000, 48000, 44100, 32000, 
                   24000, 22050, 16000, 12000, 11025, 8000, 7350 
       }; 
       channel_configuration: 表示声é“æ•°chanCfg 
       0: Defined in AOT Specifc Config 
       1: 1 channel: front-center 
       2: 2 channels: front-left, front-right 
       3: 3 channels: front-center, front-left, front-right 
       4: 4 channels: front-center, front-left, front-right, back-center 
       5: 5 channels: front-center, front-left, front-right, back-left, back-right 
       6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel 
       7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel 
       8-15: Reserved 
       */  
  
       // fill in ADTS data  
       adts[0] = (uint8_t)0xFF;  
       adts[1] = (uint8_t)0xF1;
       adts[2] = (uint8_t)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));  
       adts[3] = (uint8_t)(((chanCfg&3)<<6) + (packetLen>>11));  
       adts[4] = (uint8_t)((packetLen&0x7FF) >> 3);  
       adts[5] = (uint8_t)(((packetLen&7)<<5) + 0x1F);  
       adts[6] = (uint8_t)0xFC; 
}

void addADTStoPacket2(CAAC_RTP_UNPACK *self, uint8_t* adts_header, int frame_length) {  
	unsigned int profile = 1; // aac -lc  ,[profile, the MPEG-4 Audio Object Type minus 1]

	unsigned int num_data_block = frame_length / 1024;

	unsigned int freqIdx = 4;
	unsigned int chanCfg = 2;
	// include the header length also

	//frame_length += 7;

	/* We want the same metadata */

	/* Generate ADTS header */

	if(adts_header == NULL) return;

	/* Sync point over a full byte */

	adts_header[0] = 0xFF;

	/* Sync point continued over first 4 bits + 4 bits
		
	* ID:MPEG Version: 0 for MPEG-4, 1 for MPEG-2

	* (ID, layer, protection) = (0, 00, 1)

	*/

	adts_header[1] = 0xF1;

	/* Object type over first 2 bits */

	adts_header[2] = profile << 6;//

	/* rate index over next 4 bits */

	adts_header[2] |= (freqIdx << 2);

	/* channels over last 2 bits */

	adts_header[2] |= (chanCfg & 0x4) >> 2;

	/* channels continued over next 2 bits + 4 bits at zero */

	adts_header[3] = (chanCfg & 0x3) << 6;

	/* frame size over last 2 bits */

	adts_header[3] |= (frame_length & 0x1800) >> 11;

	/* frame size continued over full byte */

	adts_header[4] = (frame_length & 0x1FF8) >> 3;

	/* frame size continued first 3 bits */

	adts_header[5] = (frame_length & 0x7) << 5;

	/* buffer fullness (0x7FF for VBR) over 5 last bits*/

	adts_header[5] |= 0x1F;

	/* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros

	* number of raw data blocks */

	adts_header[6] = 0xFC; // one raw data blocks .

	adts_header[6] |= num_data_block & 0x03; //Set raw Data blocks.
}




//********************************* H264 END ****/



//********************************* RESAMPLE ****/



#define INBUF_SIZE 4096
#define H264_RTP_PAYLOAD_SIZE	1320
#define TEST_SAVE_H264 0

 
int initEncoder(RTPResampleTask *this);
int initDecoder(RTPResampleTask *this);

void deInitEncoder(RTPResampleTask *this);
void deInitDecoder(RTPResampleTask *this);

int decodePacket(RTPResampleTask *this, const char *inputBuffer, int inputSize);
int encodePacket(RTPResampleTask *this); 

void initRTPResampleTask(RTPResampleTask *this, const DstVideoInfo *dstVideoInfo, const SourceVideoInfo *sourceVideoInfo, EncodedCallbackFunc func , void *funcArgs){
	if (this == NULL || dstVideoInfo == NULL || sourceVideoInfo == NULL){
		return;
	}
    uint8_t szDecodedSPS[128] = { 0 };
    this->decoderHandler.sps_len = av_base64_decode((uint8_t*)szDecodedSPS, (const char *)sourceVideoInfo->sps, sizeof(szDecodedSPS));//nSPSLen=24
    this->decoderHandler.szSourceDecodedSPS = (char *)malloc(this->decoderHandler.sps_len);
	if (this->decoderHandler.szSourceDecodedSPS != NULL){
		memcpy(this->decoderHandler.szSourceDecodedSPS, szDecodedSPS, this->decoderHandler.sps_len);
	}

    uint8_t szDecodedPPS[128] = { 0 };
    this->decoderHandler.pps_len = av_base64_decode(( uint8_t*)szDecodedPPS, (const char *)sourceVideoInfo->pps, sizeof(szDecodedPPS));//nPPSLen=4
    this->decoderHandler.szSourceDecodedPPS = (char *)malloc(this->decoderHandler.pps_len);
	if (this->decoderHandler.szSourceDecodedPPS != NULL){
		memcpy(this->decoderHandler.szSourceDecodedPPS, szDecodedPPS, this->decoderHandler.pps_len);
	}

	this->funcArgs = funcArgs;
    this->callback = func;

    this->dstVideoInfo.width = dstVideoInfo->width;
    this->dstVideoInfo.height = dstVideoInfo->height;
    this->dstVideoInfo.samplerate = dstVideoInfo->samplerate;
 
    initEncoder(this);
    initDecoder(this);
}

void deInitRTPResampleTask(RTPResampleTask *this){

    deInitEncoder(this);
    deInitDecoder(this);
}

int initEncoder(RTPResampleTask *this){
    int codec_id = AV_CODEC_ID_H264;
    
    if (codec_id == AV_CODEC_ID_H264){

    }
    this->encoderHandler.rawBuffer= NULL;
    this->encoderHandler.rawBufferSize = 0;
    this->encoderHandler.encodedBuffer= NULL;
    this->encoderHandler.encodedBufferSize = 0;
    this->encoderHandler.sws_ctx = NULL;

    this->encoderHandler.pkt = av_packet_alloc();
    if (!this->encoderHandler.pkt) { 
        printf("this->encoderHandler.pkt == NULL");
        return -1;
    }
    this->encoderHandler.codec = avcodec_find_encoder(codec_id); //AV_CODEC_ID_AAC;
    if(this->encoderHandler.codec == NULL ) {
        printf("this->encoderHandler.codec == NULL");
        return -1;
    } 
    //创建AVFormatContext结构体
    //分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行  
    this->encoderHandler.context = avcodec_alloc_context3(this->encoderHandler.codec); 
    if(this->encoderHandler.context == NULL ) {
        printf("this->encoderHandler.context == NULL");
        return -1;
    } 
    //设置AVCodecContext编码参数
    struct AVCodecContext *c      = this->encoderHandler.context;
    avcodec_get_context_defaults3(c, this->encoderHandler.codec);
    c->codec_id  = codec_id; 
    c->bit_rate =  this->dstVideoInfo.samplerate * 1000;//500kbps
    c->time_base.den = 25; //分母
    c->time_base.num = 1;  //分子
    /* resolution must be a multiple of two */
    c->width =  this->dstVideoInfo.width;
    c->height =  this->dstVideoInfo.height;
    /* frames per second */
    c->time_base = (AVRational){1, 25};
    c->framerate = (AVRational){25, 1};
    c->gop_size = 1;//
    c->max_b_frames = 0;
	//c->rtp_payload_size = H264_RTP_PAYLOAD_SIZE;
    c->pix_fmt = AV_PIX_FMT_YUV420P;
    c->codec_type = AVMEDIA_TYPE_VIDEO; 
    //c->flags|= CODEC_FLAG_GLOBAL_HEADER; 
    //AVOptions的参数
    av_opt_set(c->priv_data, "preset", "slow", 0);
    av_opt_set(c->priv_data, "preset", "ultrafast", 0);
    av_opt_set(c->priv_data, "tune","stillimage,fastdecode,zerolatency",0);
    av_opt_set(c->priv_data, "x264opts","crf=26:vbv-maxrate=728:vbv-bufsize=364:keyint=25",0); 

    this->encoderHandler.frame = av_frame_alloc();
    if(this->encoderHandler.frame == NULL )  {
        printf("this->encoderHandler.frame == NULL");
        return -1;
    } 
    this->encoderHandler.frame->format = c->pix_fmt;
    this->encoderHandler.frame->width  = c->width;
    this->encoderHandler.frame->height = c->height;

 
    avpicture_alloc((AVPicture *)this->encoderHandler.frame,AV_PIX_FMT_YUV420P, this->encoderHandler.frame->width, this->encoderHandler.frame->height);  //desW,desH分别为目标分辨率的宽度、高度

    /* open it */
    int ret = avcodec_open2(this->encoderHandler.context, this->encoderHandler.codec , NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open codec: %d\n", ret);
        return -1;
    }

#ifdef TEST_SAVE_H264
    this->encoderHandler.fTest  = fopen("/tmp/test_out.h264", "wb");
    if (!this->encoderHandler.fTest) {
        fprintf(stderr, "Could not open /tmp/test_out.h264 \n");
        return -1;
    }
#endif    

    this->encoderHandler.sps = NULL;
    this->encoderHandler.sps_len = 0;
    this->encoderHandler.pps = NULL;
    this->encoderHandler.pps_len = 0;

	return 0;
}

void deInitEncoder(RTPResampleTask *this){ 
    if(this->encoderHandler.context){ 
        avcodec_free_context(&this->encoderHandler.context);
        this->encoderHandler.context = NULL;
    }
    if(this->encoderHandler.frame){
        av_frame_free(&this->encoderHandler.frame);
        this->encoderHandler.frame = NULL;
    }
    if (this->encoderHandler.pkt){
        av_packet_free(&this->encoderHandler.pkt);
        this->encoderHandler.pkt = NULL;
    }
    if (this->encoderHandler.sws_ctx){
        sws_freeContext(this->encoderHandler.sws_ctx);
        this->encoderHandler.sws_ctx = NULL;
    }
#ifdef TEST_SAVE_H264
    if (this->encoderHandler.fTest){
        fclose(this->encoderHandler.fTest);
    }
#endif
    if (this->encoderHandler.sps != NULL){
        free(this->encoderHandler.sps);
    }
    if (this->encoderHandler.pps != NULL){
        free(this->encoderHandler.pps);
    }
}


int initDecoder(RTPResampleTask *this){
    int codec_id = AV_CODEC_ID_H264;
    
    if (codec_id == AV_CODEC_ID_H264){

    }
    this->decoderHandler.pkt = av_packet_alloc();
    if (!this->decoderHandler.pkt) { 
        printf("this->decoderHandler.pkt == NULL");
        return -1;
    }

    this->decoderHandler.codec = avcodec_find_decoder(codec_id); //AV_CODEC_ID_AAC;
    if(this->decoderHandler.codec == NULL )
    {
        printf("this->decoderHandler.codec == NULL");
        return -1;
    } 
    this->decoderHandler.parser = av_parser_init(this->decoderHandler.codec->id);
    if (!this->decoderHandler.parser) { 
        printf("this->decoderHandler.parser == NULL");
        return -1;
    }
    //创建AVFormatContext结构体
    //分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行  
    this->decoderHandler.context = avcodec_alloc_context3(this->decoderHandler.codec); 
    if (!this->decoderHandler.context) { 
        printf("this->decoderHandler.context == NULL");
        return -1;
    }

    int sps_pps_len = this->decoderHandler.sps_len + this->decoderHandler.pps_len + 6;
    unsigned char *szSPSPPS = (unsigned char *)av_mallocz(sps_pps_len + 1);
    char spsHeader[4] = {0x00, 0x00,0x00,  0x01};
    char ppsHeader[3] = {0x00, 0x00, 0x01};
    memcpy(szSPSPPS, spsHeader, sizeof(spsHeader));
    memcpy(szSPSPPS + sizeof(spsHeader), this->decoderHandler.szSourceDecodedSPS, this->decoderHandler.sps_len);
    memcpy((void *)(szSPSPPS + sizeof(spsHeader)  + this->decoderHandler.sps_len), ppsHeader, sizeof(ppsHeader));
    memcpy((void *)(szSPSPPS + sizeof(spsHeader)  + sizeof(ppsHeader) + this->decoderHandler.sps_len), this->decoderHandler.szSourceDecodedPPS, this->decoderHandler.pps_len);

    this->decoderHandler.context->extradata_size = sps_pps_len;
    this->decoderHandler.context->extradata = (uint8_t*)av_mallocz(this->decoderHandler.context->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
    memcpy(this->decoderHandler.context->extradata, szSPSPPS, sps_pps_len);

    this->decoderHandler.context->time_base.num = 1;
    this->decoderHandler.context->time_base.den = 25;
    if (avcodec_open2(this->decoderHandler.context, this->decoderHandler.codec, NULL) < 0) {
           
        printf("avcodec_open2 return failed");
        return -1;
    }
    this->decoderHandler.frame = av_frame_alloc();
    if (!this->decoderHandler.frame) { 
        printf("this->decoderHandler.frame is null.");
        return -1;
    }
        
    printf("initDecoder, width:%d, height:%d", this->decoderHandler.context->width, this->decoderHandler.context->height);
    return 0;
}

void deInitDecoder(RTPResampleTask *this){
    if(this->decoderHandler.frame){
        av_frame_free(&this->decoderHandler.frame);
        this->decoderHandler.frame = NULL;
    }    
    if(this->decoderHandler.parser){
        av_parser_close(this->decoderHandler.parser);
        this->decoderHandler.parser = NULL;
    }
    if (this->decoderHandler.pkt){
        av_packet_free(&this->decoderHandler.pkt);
    }
    if (this->decoderHandler.context->extradata != NULL){
        av_free(this->decoderHandler.context->extradata);
    }
    if(this->decoderHandler.context){
        avcodec_free_context(&this->decoderHandler.context); 
        this->decoderHandler.context = NULL;
    }

}  

int resample(RTPResampleTask *this, const char *inputBuffer, int inputSize, char **outputBuffer, int *outputSize){
    *outputBuffer = NULL;
    *outputSize = 0;
    int ret = decodePacket(this, (const char *)inputBuffer, inputSize);
    //printf("video resample decodePacket ret:%d outputSize:%d\n", ret, this->encoderHandler.rawBufferSize);
    if (ret == 0 && outputSize > 0){
        char *encodeOutputBuffer = NULL;
        int encodeOutputSize = 0; 
        //scale
        if (this->encoderHandler.sws_ctx == NULL){
            this->encoderHandler.sws_ctx = sws_getContext(this->decoderHandler.context->width, this->decoderHandler.context->height, this->decoderHandler.context->pix_fmt,
                             this->encoderHandler.context->width, this->encoderHandler.context->height, AV_PIX_FMT_YUV420P,
                             SWS_BILINEAR, NULL, NULL, NULL);
        }
        sws_scale(this->encoderHandler.sws_ctx,  this->decoderHandler.frame->data,
                  this->decoderHandler.frame->linesize, 0, this->decoderHandler.context->height, this->encoderHandler.frame->data, this->encoderHandler.frame->linesize);

        ret = encodePacket(this);
        if (ret != 0){
            printf("video resample ret:%d err\n", ret);
            return -1;
        } 

#ifdef TEST_SAVE_H264
        fwrite(this->encoderHandler.encodedBuffer, 1, this->encoderHandler.encodedSize, this->encoderHandler.fTest);
#endif//#ifdef TEST_SAVE_H264

        *outputBuffer = this->encoderHandler.encodedBuffer;
        *outputSize = this->encoderHandler.encodedSize;
        int typeIndex = 3;//default 00 00 01 
        if (this->encoderHandler.encodedBuffer[3] == 0x01){
            typeIndex = 4;
        }
        
        if (this->encoderHandler.encodedBuffer[typeIndex] == 0x67  && this->encoderHandler.sps == NULL){
            printf("video resample has sps:%d  \n", this->encoderHandler.encodedSize);  
            this->encoderHandler.sps_len = 0;
            int i = 0;
            unsigned short find_sps_flag = 0;
            while(i++ < this->encoderHandler.encodedSize){
                if ((this->encoderHandler.encodedBuffer[typeIndex] == 0x00 &&
                this->encoderHandler.encodedBuffer[typeIndex + 1] == 0x00 && 
                this->encoderHandler.encodedBuffer[typeIndex + 2] == 0x01 && 
                this->encoderHandler.encodedBuffer[typeIndex + 3] == 0x68)
                ){
                    find_sps_flag = 1;
                    break;
                }
                typeIndex++;
            }      
            if (!find_sps_flag){
                return 0;    
            }
            find_sps_flag = 0;

            this->encoderHandler.sps_len = typeIndex;
            printf("video resample this->encoderHandler.sps_len:%d  \n", this->encoderHandler.sps_len);  
            
            this->encoderHandler.sps = (char *)malloc(this->encoderHandler.sps_len);
            if (this->encoderHandler.sps != NULL){
                memcpy((void *)this->encoderHandler.sps, (void *)this->encoderHandler.encodedBuffer, this->encoderHandler.sps_len);
            }
            this->encoderHandler.pps_len = 0;
            typeIndex = this->encoderHandler.sps_len + 4;
            while(i++ < this->encoderHandler.encodedSize){
                if (
                    (this->encoderHandler.encodedBuffer[typeIndex] == 0x00 &&
                    this->encoderHandler.encodedBuffer[typeIndex +1] == 0x00 &&  
                    this->encoderHandler.encodedBuffer[typeIndex +2] == 0x01)
                ){
                    find_sps_flag = 1;
                    break;
                }
                typeIndex++;
                this->encoderHandler.pps_len++;
            }     
            if (!find_sps_flag){
                return 0;    
            }
            this->encoderHandler.pps_len += 4;

            printf("video resample this->encoderHandler.pps_len:%d  \n", this->encoderHandler.pps_len);   
            this->encoderHandler.pps = (char *)malloc(this->encoderHandler.pps_len);
            if (this->encoderHandler.pps != NULL){
                memcpy((void *)this->encoderHandler.pps, &this->encoderHandler.encodedBuffer[this->encoderHandler.sps_len], this->encoderHandler.pps_len);
            } 
        }
        return 0;  
    } 
        
    return -1; 
}

int decodePacket(RTPResampleTask *this, const char *inputBuffer, int inputSize){
 
    int ret;  
    uint8_t *data = ( uint8_t *)inputBuffer;
    int data_size = inputSize;
    //while (data_size > 0) 
    { 
        this->encoderHandler.rawBufferSize =   0;
        av_init_packet(this->decoderHandler.pkt);
        this->decoderHandler.pkt->dts  = AV_NOPTS_VALUE;
        this->decoderHandler.pkt->size = (int)inputSize;
        this->decoderHandler.pkt->data = (uint8_t *)inputBuffer;  
        if (this->decoderHandler.pkt->size){
		    ret = avcodec_send_packet(this->decoderHandler.context, this->decoderHandler.pkt);
		    if (ret < 0) {
		        fprintf(stderr, "decodePacket Error sending a packet for decoding, size:%d %02x %02x %02x %02x %02x  \n", inputSize, *(inputBuffer), *(inputBuffer+1), *(inputBuffer+2), *(inputBuffer+3), *(inputBuffer+4));
		        return 1;
		    }
 
	        ret = avcodec_receive_frame(this->decoderHandler.context, this->decoderHandler.frame);
	        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){  
	            return 1;
	        }
	        else if (ret < 0) {
	            fprintf(stderr, "decodePacket Error during decoding :%d\n", ret);
	            return 1;
	        } 
	    	int xsize = avpicture_get_size(this->decoderHandler.context->pix_fmt, this->decoderHandler.context->width, this->decoderHandler.context->height);	
            //fprintf(stderr, "decodePacket end decoding :%d, width:%d, height:%d\n", xsize, this->decoderHandler.context->width, this->decoderHandler.context->height);
            this->encoderHandler.rawBufferSize = xsize;
            //
        }else{ 
        	return -1;
        }
    }
 
	return 0;
}

int encodePacket(RTPResampleTask *this){
    #if 0
    int size = avpicture_fill((AVPicture*)this->encoderHandler.frame, (uint8_t*)inputBuffer, AV_PIX_FMT_YUV420P, this->encoderHandler.context->width, this->encoderHandler.context->height);
    if (size != inputSize){
        /* guard */
        printf("encodePacket invalid size: %u<>%u", size, inputSize);
        return 0;
    }
    #endif//this->encoderHandler.frame
    int ret = avcodec_send_frame(this->encoderHandler.context, this->encoderHandler.frame);
    if (ret < 0) {
        printf("encodePacket error sending a frame for encoding, ret:%d\n", ret);
        return ret;
    }

    this->encoderHandler.encodedSize = 0;

    while (ret >= 0) 
    {
        ret = avcodec_receive_packet(this->encoderHandler.context, this->encoderHandler.pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){ 
            if (this->encoderHandler.encodedSize > 0){
                return 0;
            }
            return -1;
        } else if (ret < 0) {
            printf("encodePacket error during encoding\n");
            return ret;
        }
        if (this->encoderHandler.encodedBuffer == NULL){ 
            this->encoderHandler.encodedBuffer = (char *)malloc((this->encoderHandler.context->width*this->encoderHandler.context->height * 3)/2);   
            this->encoderHandler.encodedBufferSize = (this->encoderHandler.context->width*this->encoderHandler.context->height * 3)/2;
        }

        if (this->encoderHandler.encodedBufferSize < (this->encoderHandler.pkt->size + this->encoderHandler.encodedSize)){ 
            this->encoderHandler.encodedBuffer = (char *)realloc(this->encoderHandler.encodedBuffer, this->encoderHandler.pkt->size + this->encoderHandler.encodedSize); 
            this->encoderHandler.encodedBufferSize += this->encoderHandler.pkt->size + this->encoderHandler.encodedSize;
        }
    	if (this->encoderHandler.encodedBuffer){
    		memcpy((void *)(this->encoderHandler.encodedBuffer + this->encoderHandler.encodedSize), this->encoderHandler.pkt->data, this->encoderHandler.pkt->size);
    	}
        this->encoderHandler.encodedSize += this->encoderHandler.pkt->size;
        //printf("encodePacket success ret:%d\n", this->encoderHandler.pkt->size); 
        //if (callback != NULL){
            //callback(funcArgs, (char*)this->encoderHandler.pkt->data, this->encoderHandler.pkt->size);
        //}
        av_packet_unref(this->encoderHandler.pkt);
    }
    //printf("encodePacket success ret:%d\n", this->encoderHandler.encodedBufferSize); 
	return 0;
}
 

//********************************* RESAMPLE END ****/

发布了73 篇原创文章 · 获赞 26 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/twoconk/article/details/89103021