3、FFmpeg编解码

1、视频编码

环境配了半天(下午到晚上)。具体怎么配好我也不记得了,,就一通乱下
下载x264后要重新编译ffmpeg ./configure --enable-shared --enable-libx264 --enable-gpl --enable-pthreads

#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>

static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){
    int ret = -1;

    ret = avcodec_send_frame(ctx, frame);
    if(ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder!\n");
        goto _END;
    }

    while( ret >= 0){
        ret = avcodec_receive_packet(ctx, pkt);
        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
            return 0;
        } else if( ret < 0) {
            return -1; //退出tkyc
        }

        fwrite(pkt->data, 1, pkt->size, out);
        av_packet_unref(pkt);
    }
_END:
    return 0;
}

int main(int argc, char* argv[]){

    int ret = -1;

    FILE *f = NULL;

    char *dst = NULL;
    char *codecName = NULL;

    const AVCodec *codec = NULL;
    AVCodecContext *ctx = NULL;

    AVFrame *frame = NULL;
    AVPacket *pkt = NULL;

    av_log_set_level(AV_LOG_DEBUG);

    //1. 输入参数
    if(argc < 3){
        av_log(NULL, AV_LOG_ERROR, "arguments must be more than 3\n");
        goto _ERROR;
    }

    dst = argv[1];
    codecName = argv[2];

    //2. 查找编码器
    codec = avcodec_find_encoder_by_name(codecName);
    if(!codec){
        av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
        goto _ERROR;
    }

    //3. 创建编码器上下文
    ctx = avcodec_alloc_context3(codec);
    if(!ctx){
        av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
        goto _ERROR;
    }

    //4. 设置编码器参数
    ctx->width = 640;
    ctx->height = 480;
    ctx->bit_rate = 500000;

    ctx->time_base = (AVRational){1, 25};
    ctx->framerate = (AVRational){25, 1};

    ctx->gop_size = 10;
    ctx->max_b_frames = 1;
    ctx->pix_fmt = AV_PIX_FMT_YUV420P;

    if(codec->id == AV_CODEC_ID_H264){
        av_opt_set(ctx->priv_data, "preset", "slow", 0);
    }

    //5. 编码器与编码器上下文绑定到一起
    ret = avcodec_open2(ctx, codec , NULL);
    if(ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
        goto _ERROR;
    }

    //6. 创建输出文件
    f = fopen(dst, "wb");
    if(!f){
        av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
        goto _ERROR;
    }

    //7. 创建AVFrame
    frame = av_frame_alloc();
    if(!frame){
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }
    frame->width = ctx->width;
    frame->height = ctx->height;
    frame->format = ctx->pix_fmt; 

    ret = av_frame_get_buffer(frame, 0);
    if(ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
        goto _ERROR;
    }

    //8. 创建AVPacket
    pkt = av_packet_alloc();
     if(!pkt){
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    //9. 生成视频内容
    for(int i=0; i<25; i++){
        ret = av_frame_make_writable(frame);
        if(ret < 0) {
            break;
        }

        //Y分量
        for(int y = 0; y < ctx->height; y++){
            for(int x=0; x < ctx->width; x++){
                frame->data[0][y*frame->linesize[0]+x] = x + y + i * 3;
            }
        }

        //UV分量
        for(int y=0; y< ctx->height/2; y++){
            for(int x=0; x < ctx->width/2; x++){
                frame->data[1][y * frame->linesize[1] + x ] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x ] = 64 + x + i * 4;
            }
        }

        frame->pts = i;

        //10. 编码
        ret = encode(ctx, frame, pkt, f);
        if(ret == -1){
            goto _ERROR;
        }
    }
    //10. 编码
    encode(ctx, NULL, pkt, f);
_ERROR:
    //ctx
    if(ctx){
        avcodec_free_context(&ctx);
    }

    //avframe
    if(frame){
        av_frame_free(&frame);
    }

    //avpacket
    if(pkt){
        av_packet_free(&pkt);
    }

    //dst
    if(f){
        fclose(f);
    }
    return 0;
}

file

2、音频编码

#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavutil/samplefmt.h>

#include <libavcodec/avcodec.h>

static int select_best_sample_rate(const AVCodec *codec){
    const int *p;
    int best_samplerate = 0;

    if(!codec->supported_samplerates){
        return 44100;
    }
    p = codec->supported_samplerates;
    while(*p){
        if(!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate)){
            best_samplerate = *p;
        }
        p++;
    }
    return best_samplerate;
}

static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt){
    const enum AVSampleFormat *p = codec->sample_fmts;

    while(*p != AV_SAMPLE_FMT_NONE){
        if( *p == sample_fmt) {
            return 1;
        }
        p++;
    }
    return 0;

}

static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){
    int ret = -1;

    ret = avcodec_send_frame(ctx, frame);
    if(ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder: %s!\n", av_err2str(ret));
        goto _END;
    }

    while( ret >= 0){
        ret = avcodec_receive_packet(ctx, pkt);
        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
            return 0;
        } else if( ret < 0) {
            return -1; //退出tkyc
        }
        av_log(NULL, AV_LOG_DEBUG, "ptk.size:%d\n", pkt->size);
        fwrite(pkt->data, 1, pkt->size, out);
        av_packet_unref(pkt);
    }
_END:
    return 0;
}

int main(int argc, char* argv[]){

    int ret = -1;

    FILE *f = NULL;

    char *dst = NULL;
    char *codecName = NULL;

    const AVCodec *codec = NULL;
    AVCodecContext *ctx = NULL;

    AVFrame *frame = NULL;
    AVPacket *pkt = NULL;

    uint16_t *samples = NULL;

    av_log_set_level(AV_LOG_DEBUG);

    //1. 输入参数
    if(argc < 2){
        av_log(NULL, AV_LOG_ERROR, "arguments must be more than 2\n");
        goto _ERROR;
    }

    dst = argv[1];
    //codecName = argv[2];

    //2. 查找编码器
    //codec = avcodec_find_encoder_by_name(codecName);
    codec = avcodec_find_encoder_by_name("libfdk_aac");
    //codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if(!codec){
        av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
        goto _ERROR;
    }

    //3. 创建编码器上下文
    ctx = avcodec_alloc_context3(codec);
    if(!ctx){
        av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
        goto _ERROR;
    } 

    //4. 设置编码器参数
    ctx->bit_rate = 64000;
    ctx->sample_fmt = AV_SAMPLE_FMT_S16;//AV_SAMPLE_FMT_FLTP
    if(!check_sample_fmt(codec, ctx->sample_fmt)){
        av_log(NULL, AV_LOG_ERROR, "Encoder does not support sample format!\n");
        goto _ERROR;
    }

    ctx->sample_rate = select_best_sample_rate(codec);
    av_channel_layout_copy(&ctx->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO

    //5. 编码器与编码器上下文绑定到一起
    ret = avcodec_open2(ctx, codec , NULL);
    if(ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
        goto _ERROR;
    }

    //6. 创建输出文件
    f = fopen(dst, "wb");
    if(!f){
        av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
        goto _ERROR;
    }

    //7. 创建AVFrame
    frame = av_frame_alloc();
    if(!frame){
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    frame->nb_samples = ctx->frame_size;
    frame->format = AV_SAMPLE_FMT_S16; //AV_SAMPLE_FMT_FLTP
    av_channel_layout_copy(&frame->ch_layout,  &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO
    frame->sample_rate = ctx->sample_rate;
    ret = av_frame_get_buffer(frame, 0);
    if(ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
        goto _ERROR;
    }

    //8. 创建AVPacket
    pkt = av_packet_alloc();
     if(!pkt){
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    //9. 生成音频内容
    float t = 0;
    float tincr = 4*M_PI*440/ctx->sample_rate;

    for(int i=0; i < 200; i++){
        ret = av_frame_make_writable(frame);
        if(ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Could not allocate space!\n");
            goto _ERROR;
        }

        samples = (uint16_t*)frame->data[0]; //FLTP 32 (uint32_t*)
        for(int j=0; j < ctx->frame_size; j++){
            samples[2*j] = (int)((t)*10000); //4
            for(int k=1; k < ctx->ch_layout.nb_channels; k++){
                samples[2*j + k] = samples[2*j]; //4
            }
            t += tincr;
        }
        encode(ctx, frame, pkt, f);
    }
    //10. 编码
    encode(ctx, NULL, pkt, f);
_ERROR:
    //ctx
    if(ctx){
        avcodec_free_context(&ctx);
    }

    //avframe
    if(frame){
        av_frame_free(&frame);
    }

    //avpacket
    if(pkt){
        av_packet_free(&pkt);
    }

    //dst
    if(f){
        fclose(f);
    }
    return 0;
}

3、视频抽取图片

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>

#define WORD uint16_t
#define DWORD uint32_t
#define LONG int32_t

#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
  WORD  bfType;
  DWORD bfSize;
  WORD  bfReserved1;
  WORD  bfReserved2;
  DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG  biWidth;
  LONG  biHeight;
  WORD  biPlanes;
  WORD  biBitCount;
  DWORD biCompression;
  DWORD biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

void saveBMP(struct SwsContext *img_convert_ctx, AVFrame *frame, int w, int h, char *filename)
{
    //1 先进行转换,  YUV420=>RGB24:
    // int w = img_convert_ctx->frame_dst->width;
    // int h = img_convert_ctx->frame_dst->height;

    int data_size = w * h * 3;

    AVFrame *pFrameRGB = av_frame_alloc();

    //avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, w, h);
    pFrameRGB->width = w;
    pFrameRGB->height = h;
    pFrameRGB->format =  AV_PIX_FMT_BGR24;

    av_frame_get_buffer(pFrameRGB, 0);

    sws_scale(img_convert_ctx, 
              (const uint8_t* const *)frame->data, 
              frame->linesize,
              0, frame->height, pFrameRGB->data, pFrameRGB->linesize);

    //2 构造 BITMAPINFOHEADER
    BITMAPINFOHEADER header;
    header.biSize = sizeof(BITMAPINFOHEADER);

    header.biWidth = w;
    header.biHeight = h*(-1);
    header.biBitCount = 24;
    header.biCompression = 0;
    header.biSizeImage = 0;
    header.biClrImportant = 0;
    header.biClrUsed = 0;
    header.biXPelsPerMeter = 0;
    header.biYPelsPerMeter = 0;
    header.biPlanes = 1;

    //3 构造文件头
    BITMAPFILEHEADER bmpFileHeader = {0,};
    //HANDLE hFile = NULL;
    DWORD dwTotalWriten = 0;
    DWORD dwWriten;

    bmpFileHeader.bfType = 0x4d42; //'BM';
    bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ data_size;
    bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);

    FILE* pf = fopen(filename, "wb");
    fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
    fwrite(&header, sizeof(BITMAPINFOHEADER), 1, pf);
    fwrite(pFrameRGB->data[0], 1, data_size, pf);
    fclose(pf);

    //释放资源
    //av_free(buffer);
    av_freep(&pFrameRGB[0]);
    av_free(pFrameRGB);
}

static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
                     char *filename)
{
    FILE *f;
    int i;

    f = fopen(filename,"w");
    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);
    fclose(f);
}

static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
                              struct SwsContext *img_convert_ctx, AVFrame *frame, AVPacket *pkt)
{
    int ret = -1;
    char buf[1024];

    ret = avcodec_send_packet(avctx, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error while decoding frame, %s(%d)\n", av_err2str(ret), ret);
        return ret;
    }

    while (ret >= 0) {
        fflush(stdout);

        ret = avcodec_receive_frame(avctx, frame);
        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
            return 0;
        }else if( ret < 0){
            return -1;
        }

        /* the picture is allocated by the decoder, no need to free it */
        snprintf(buf, sizeof(buf), "%s-%d.bmp", outfilename, avctx->frame_number);
        /*pgm_save(frame->data[0], frame->linesize[0],
                 frame->width, frame->height, buf);*/

        saveBMP(img_convert_ctx, frame, 160,  120, buf);

    }
    return 0;
}

int main(int argc, char **argv)
{
    int ret;
    int idx;

    const char *filename, *outfilename;

    AVFormatContext *fmt_ctx = NULL;

    const AVCodec *codec = NULL;
    AVCodecContext *ctx = NULL;

    AVStream *inStream = NULL;

    AVFrame *frame = NULL;  
    AVPacket avpkt;

    struct SwsContext *img_convert_ctx;

    if (argc <= 2) {
        fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
        exit(0);
    }
    filename    = argv[1];
    outfilename = argv[2];

    /* open input file, and allocate format context */
    if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source file %s\n", filename);
        exit(1);
    }

    /* retrieve stream information */
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }

    /* dump input information to stderr */
    //av_dump_format(fmt_ctx, 0, filename, 0);

    //av_init_packet(&avpkt);

    /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
    //memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    //

    idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (idx < 0) {
        fprintf(stderr, "Could not find %s stream in input file '%s'\n",
                av_get_media_type_string(AVMEDIA_TYPE_VIDEO), filename);
        return idx;
    }

    inStream = fmt_ctx->streams[idx];

    /* find decoder for the stream */
    codec = avcodec_find_decoder(inStream->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Failed to find %s codec\n",
                av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
        return AVERROR(EINVAL);
    }

    ctx = avcodec_alloc_context3(NULL);
    if (!ctx) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }

    /* Copy codec parameters from input stream to output codec context */
    if ((ret = avcodec_parameters_to_context(ctx, inStream->codecpar)) < 0) {
        fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
                av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
        return ret;
    }

    /* open it */
    if (avcodec_open2(ctx, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    img_convert_ctx = sws_getContext(ctx->width, ctx->height,
                                     ctx->pix_fmt,
                                     160, 120,
                                     AV_PIX_FMT_BGR24,
                                     SWS_BICUBIC, NULL, NULL, NULL);

    if (img_convert_ctx == NULL)
    {
        fprintf(stderr, "Cannot initialize the conversion context\n");
        exit(1);
    }

    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }

    while (av_read_frame(fmt_ctx, &avpkt) >= 0) {
        if(avpkt.stream_index == idx){
            if (decode_write_frame(outfilename, ctx, img_convert_ctx, frame, &avpkt) < 0)
                exit(1);
        }

        av_packet_unref(&avpkt);
    }

    decode_write_frame(outfilename, ctx, img_convert_ctx, frame, NULL);

    avformat_close_input(&fmt_ctx);

    sws_freeContext(img_convert_ctx);
    avcodec_free_context(&ctx);
    av_frame_free(&frame);

    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇