ffmpeg+SDL2实现的音频播放器V2.0(无杂音)

1. 前言

目前为止,学习了并记录了ffmpeg+SDL2显示视频以及事件(event)的内容。 
这篇中记录ffmpeg+SDL2播放音频,没加入事件处理。 
接下来加入事件处理并继续学习音视频同步,再接下来就添加暂停之类的或者添个界面。

2. 流程图

这里写图片描述

3. 示例


示例代码的主要思想是:(和音频播放器V1.0思想一样,实现不同。不同在于这个程序用一个队列存储主线程读到的AVPacket)

  • 主线程只负责读AVPacket存到队列。—>av_read_frame()
  • 其他所有的解码,输出工作都由callback完成。 
    • callback中从队列中取AVPacketList,再把AVPacketList中的AVPacket拿出来解码。
    • 解码后放到缓冲区,然后输出。
    • 一次调用callback,就输出长度为len的数据(callback第三个参数,一般为2048),不多不少。
    • 当缓冲区没有数据的时候,就去解码,放到缓冲区,再输出。
    • 当解码的数据多于len的时候,就只处理len个,其他的留给后续的callback。
    • callback函数会一次次调用,直到所有处理完。 

详见代码及代码中注释

注意:

  • 链表结构是AVPacketList,含两个成员: 
    • AVPacket packet;
    • AVPacketList *next;
  • 代码中注释掉的代码(块注释的),是不用也可以正常运行的,要可能更健壮之类的。

3.1 代码

(所有代码都贴了,较长,后面有代码下载地址)

  • audio_player_v2.0.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>

#define __STDC_CONSTANT_MACROS      //ffmpeg要求

#ifdef __cplusplus
extern "C"
{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>

#ifdef __cplusplus
}
#endif

//
#include "wrap_base.h"
#include "packet_queue.h"

#define AVCODE_MAX_AUDIO_FRAME_SIZE    192000  //1 second of 48khz 32bit audio
#define SDL_AUDIO_BUFFER_SIZE   1024    //

#define FILE_NAME               "/home/isshe/Music/WavinFlag.aac"
#define ERR_STREAM              stderr
#define OUT_SAMPLE_RATE         44100

AVFrame         wanted_frame;
PacketQueue     audio_queue;
int      quit = 0;

void audio_callback(void *userdata, Uint8 *stream, int len);
int audio_decode_frame(AVCodecContext *pcodec_ctx, uint8_t *audio_buf, int buf_size);
/*
void packet_queue_init(PacketQueue *queue);
int packet_queue_put(PacketQueue *queue, AVPacket *packet);
int packet_queue_get(PacketQueue *queue, AVPacket *packet, int block);
*/
int main(int argc, char *argv[])
{
    AVFormatContext     *pformat_ctx = NULL;
    int                 audio_stream = -1;
    AVCodecContext      *pcodec_ctx = NULL;
    AVCodecContext      *pcodec_ctx_cp = NULL;
    AVCodec             *pcodec = NULL;
    AVPacket            packet ;        //!
    AVFrame             *pframe = NULL;
    char                filename[256] = FILE_NAME;

    //SDL
    SDL_AudioSpec       wanted_spec;
    SDL_AudioSpec       spec ;

    //ffmpeg 初始化
    av_register_all();

    //SDL初始化
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
    {
        fprintf(ERR_STREAM, "Couldn't init SDL:%s\n", SDL_GetError());
        exit(-1);
    }

    get_file_name(filename, argc, argv);

    //打开文件
    if (avformat_open_input(&pformat_ctx, filename, NULL, NULL) != 0)
    {
         fprintf(ERR_STREAM, "Couldn't open input file\n");
         exit(-1);
    }

    //检测文件流信息
    //旧版的是av_find_stream_info()
    if (avformat_find_stream_info(pformat_ctx, NULL) < 0)
    {
         fprintf(ERR_STREAM, "Not Found Stream Info\n");
         exit(-1);
    }

    //显示文件信息,十分好用的一个函数
    av_dump_format(pformat_ctx, 0, filename, false);

    //找视音频流
    if (find_stream_index(pformat_ctx, NULL, &audio_stream) == -1)
    {
        fprintf(ERR_STREAM, "Couldn't find stream index\n");
        exit(-1);
    }
    printf("audio_stream = %d\n", audio_stream);

    //找到对应的解码器
    pcodec_ctx = pformat_ctx->streams[audio_stream]->codec;
    pcodec = avcodec_find_decoder(pcodec_ctx->codec_id);
    if (!pcodec)
    {
         fprintf(ERR_STREAM, "Couldn't find decoder\n");
         exit(-1);
    }

/*
    pcodec_ctx_cp = avcodec_alloc_context3(pcodec);
    if (avcodec_copy_context(pcodec_ctx_cp, pcodec_ctx) != 0)
    {
        fprintf(ERR_STREAM, "Couldn't copy codec context\n");
        exit(-1);
    }
 */

    //设置音频信息, 用来打开音频设备。
    wanted_spec.freq        = pcodec_ctx->sample_rate;
    wanted_spec.format      = AUDIO_S16SYS;
    wanted_spec.channels    = pcodec_ctx->channels;        //通道数
    wanted_spec.silence     = 0;    //设置静音值
    wanted_spec.samples     = SDL_AUDIO_BUFFER_SIZE;        //读取第一帧后调整?
    wanted_spec.callback    = audio_callback;
    wanted_spec.userdata    = pcodec_ctx;

    //wanted_spec:想要打开的
    //spec: 实际打开的,可以不用这个,函数中直接用NULL,下面用到spec的用wanted_spec代替。
    //这里会开一个线程,调用callback。
    //SDL_OpenAudio->open_audio_device(开线程)->SDL_RunAudio->fill(指向callback函数)
    //可以用SDL_OpenAudioDevice()代替
    if (SDL_OpenAudio(&wanted_spec, &spec) < 0)
    {
        fprintf(ERR_STREAM, "Couldn't open Audio:%s\n", SDL_GetError());
        exit(-1);
    }

    //设置参数,供解码时候用, swr_alloc_set_opts的in部分参数
    wanted_frame.format         = AV_SAMPLE_FMT_S16;
    wanted_frame.sample_rate    = spec.freq;
    wanted_frame.channel_layout = av_get_default_channel_layout(spec.channels);
    wanted_frame.channels       = spec.channels;

    //初始化AVCondecContext,以及进行一些处理工作。
    avcodec_open2(pcodec_ctx, pcodec, NULL);

    //初始化队列
    packet_queue_init(&audio_queue);

    //可以用SDL_PauseAudioDevice()代替,目前用的这个应该是旧的。
    //0是不暂停,非零是暂停
    //如果没有这个就放不出声音
    SDL_PauseAudio(0);              //为什么要这个?

    //读一帧数据
    while(av_read_frame(pformat_ctx, &packet) >= 0)     //读一个packet,数据放在packet.data
    {
         if (packet.stream_index == audio_stream)
         {
             packet_queue_put(&audio_queue, &packet);
         }
         else
         {
             av_free_packet(&packet);
         }
    }
    getchar();      //...
    return 0;
}


//注意userdata是前面的AVCodecContext.
//len的值常为2048,表示一次发送多少。
//audio_buf_size:一直为样本缓冲区的大小,wanted_spec.samples.(一般每次解码这么多,文件不同,这个值不同)
//audio_buf_index: 标记发送到哪里了。
//这个函数的工作模式是:
//1. 解码数据放到audio_buf, 大小放audio_buf_size。(audio_buf_size = audio_size;这句设置)
//2. 调用一次callback只能发送len个字节,而每次取回的解码数据可能比len大,一次发不完。
//3. 发不完的时候,会len == 0,不继续循环,退出函数,继续调用callback,进行下一次发送。
//4. 由于上次没发完,这次不取数据,发上次的剩余的,audio_buf_size标记发送到哪里了。
//5. 注意,callback每次一定要发且仅发len个数据,否则不会退出。
//如果没发够,缓冲区又没有了,就再取。发够了,就退出,留给下一个发,以此循环。
//三个变量设置为static就是为了保存上次数据,也可以用全局变量,但是感觉这样更好。
void audio_callback(void *userdata, Uint8 *stream, int len)
{
     AVCodecContext *pcodec_ctx     = (AVCodecContext *)userdata;
     int len1 = 0;
     int audio_size = 0;

     //注意是static
     //为什么要分那么大?
     static uint8_t         audio_buf[(AVCODE_MAX_AUDIO_FRAME_SIZE * 3) / 2];
     static unsigned int    audio_buf_size = 0;
     static unsigned int    audio_buf_index = 0;

     //初始化stream,每次都要。
     SDL_memset(stream, 0, len);

     while(len > 0)
     {
          if (audio_buf_index >= audio_buf_size)
          {
              //数据全部发送,再去获取
              //自定义的一个函数
              audio_size = audio_decode_frame(pcodec_ctx, audio_buf, sizeof(audio_buf));
              if (audio_size < 0)
              {
                  //错误则静音
                  audio_buf_size = 1024;
                  memset(audio_buf, 0, audio_buf_size);
              }
              else
              {
                  audio_buf_size = audio_size;
              }
              audio_buf_index = 0;      //回到缓冲区开头
          }

          len1 = audio_buf_size - audio_buf_index;
//          printf("len1 = %d\n", len1);
          if (len1 > len)       //len1常比len大,但是一个callback只能发len个
          {
               len1 = len;
          }

          //新程序用 SDL_MixAudioFormat()代替
          //混合音频, 第一个参数dst, 第二个是src,audio_buf_size每次都在变化
          SDL_MixAudio(stream, (uint8_t*)audio_buf + audio_buf_index, len, SDL_MIX_MAXVOLUME);
          //
          //memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
          len -= len1;
          stream += len1;
          audio_buf_index += len1;
     }

}


//对于音频来说,一个packet里面,可能含有多帧(frame)数据。

int audio_decode_frame(AVCodecContext *pcodec_ctx,
        uint8_t *audio_buf, int buf_size)
{
     AVPacket   packet;
     AVFrame    *frame;
     int        got_frame;
     int        pkt_size = 0;
//     uint8_t    *pkt_data = NULL;
     int        decode_len;
     int        try_again = 0;
     long long  audio_buf_index = 0;
     long long  data_size = 0;
     SwrContext *swr_ctx = NULL;
     int        convert_len = 0;
     int        convert_all = 0;

     if (packet_queue_get(&audio_queue, &packet, 1) < 0)
     {
          fprintf(ERR_STREAM, "Get queue packet error\n");
          return -1;
     }

//     pkt_data = packet.data;
     pkt_size = packet.size;
//     fprintf(ERR_STREAM, "pkt_size = %d\n", pkt_size);

     frame = av_frame_alloc();
     while(pkt_size > 0)
     {
//          memset(frame, 0, sizeof(AVFrame));
          //pcodec_ctx:解码器信息
          //frame:输出,存数据到frame
          //got_frame:输出。0代表有frame取了,不意味发生了错误。
          //packet:输入,取数据解码。
          decode_len = avcodec_decode_audio4(pcodec_ctx,
                  frame, &got_frame, &packet);
          if (decode_len < 0) //解码出错
          {
               //重解, 这里如果一直<0呢?
               fprintf(ERR_STREAM, "Couldn't decode frame\n");
               if (try_again == 0)
               {
                    try_again++;
                    continue;
               }
               try_again = 0;
          }


          if (got_frame)
          {

 /*              //用定的音频参数获取样本缓冲区大小
               data_size = av_samples_get_buffer_size(NULL,
                       pcodec_ctx->channels, frame->nb_samples,
                       pcodec_ctx->sample_fmt, 1);

               assert(data_size <= buf_size);
//               memcpy(audio_buf + audio_buf_index, frame->data[0], data_size);
*/
              //chnanels: 通道数量, 仅用于音频
              //channel_layout: 通道布局。
              //多音频通道的流,一个通道布局可以具体描述其配置情况.通道布局这个概念不懂。
              //大概指的是单声道(mono),立体声道(stereo), 四声道之类的吧?
              //详见源码及:https://xdsnet.gitbooks.io/other-doc-cn-ffmpeg/content/ffmpeg-doc-cn-07.html#%E9%80%9A%E9%81%93%E5%B8%83%E5%B1%80


              if (frame->channels > 0 && frame->channel_layout == 0)
              {
                   //获取默认布局,默认应该了stereo吧?
                   frame->channel_layout = av_get_default_channel_layout(frame->channels);
              }
              else if (frame->channels == 0 && frame->channel_layout > 0)
              {
                  frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);
              }


              if (swr_ctx != NULL)
              {
                   swr_free(&swr_ctx);
                   swr_ctx = NULL;
              }

              //设置common parameters
              //2,3,4是output参数,4,5,6是input参数。
              swr_ctx = swr_alloc_set_opts(NULL, wanted_frame.channel_layout,
                      (AVSampleFormat)wanted_frame.format,
                      wanted_frame.sample_rate, frame->channel_layout,
                      (AVSampleFormat)frame->format, frame->sample_rate, 0, NULL);
              //初始化
              if (swr_ctx == NULL || swr_init(swr_ctx) < 0)
              {
                   fprintf(ERR_STREAM, "swr_init error\n");
                   break;
              }
              //av_rescale_rnd(): 用指定的方式队64bit整数进行舍入(rnd:rounding),
              //使如a*b/c之类的操作不会溢出。
              //swr_get_delay(): 返回 第二个参数分之一(下面是:1/frame->sample_rate)
              //AVRouding是一个enum,1的意思是round away from zero.
    /*
              int dst_nb_samples = av_rescale_rnd(
                      swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples,
                      wanted_frame.sample_rate, wanted_frame.format,
                      AVRounding(1));
    */

              //转换音频。把frame中的音频转换后放到audio_buf中。
              //第2,3参数为output, 第4,5为input。
              //可以使用#define AVCODE_MAX_AUDIO_FRAME_SIZE 192000 
              //把dst_nb_samples替换掉, 最大的采样频率是192kHz.
              convert_len = swr_convert(swr_ctx, 
                                &audio_buf + audio_buf_index,
                                AVCODE_MAX_AUDIO_FRAME_SIZE,
                                (const uint8_t **)frame->data, 
                                frame->nb_samples);

              printf("decode len = %d, convert_len = %d\n", decode_len, convert_len);
              //解码了多少,解码到了哪里
    //          pkt_data += decode_len;
              pkt_size -= decode_len;
              //转换后的有效数据存到了哪里,又audio_buf_index标记
              audio_buf_index += convert_len;//data_size;
              //返回所有转换后的有效数据的长度
              convert_all += convert_len;
         }
     }
     return wanted_frame.channels * convert_all * av_get_bytes_per_sample((AVSampleFormat)wanted_frame.format);
//     return audio_buf_index;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • packet_queue.h
#ifndef PACKET_QUEUE_H_
#define PACKET_QUEUE_H_

#ifdef __cplusplus
extern "C"{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>

typedef struct PacketQueue
{
    AVPacketList    *first_pkt;     //队头的一个packet, 注意类型不是AVPacket
    AVPacketList    *last_pkt;      //队尾packet
    int             nb_packets;     // paket个数
    int             size;           //
    SDL_mutex       *mutex;         //
    SDL_cond        *cond;          // 条件变量
}PacketQueue;

void packet_queue_init(PacketQueue *queue);
int packet_queue_put(PacketQueue *queue, AVPacket *packet);
int packet_queue_get(PacketQueue *queue, AVPacket *pakcet, int block);

#ifdef __cplusplus
}
#endif
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • packet_queue.c

#define __STDC_CONSTANT_MACROS      //ffmpeg要求

#ifdef __cplusplus
extern "C"
{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>

#ifdef __cplusplus
}
#endif

#include "packet_queue.h"
/*======================================================================\
* Author     (作者): i.sshe
* Date       (日期): 2016/10/03
* Others     (其他): 初始化队列
\*=======================================================================*/
void packet_queue_init(PacketQueue *queue)
{
//     memset(queue, 0, sizeof(PacketQueue));
     queue->first_pkt    = NULL;
     queue->last_pkt     = NULL;
     queue->mutex           = SDL_CreateMutex();
     queue->cond            = SDL_CreateCond();
}



/*======================================================================\
* Author     (作者): i.sshe
* Date       (日期): 2016/10/03
* Others     (其他): 入队
\*=======================================================================*/
int packet_queue_put(PacketQueue *queue, AVPacket *packet)
{
     AVPacketList   *pkt_list;

     // ???
     if (av_dup_packet(packet) < 0)
     {
         return -1;
     }

     pkt_list = (AVPacketList *)av_malloc(sizeof(AVPacketList));
     if (pkt_list == NULL)
     {
          return -1;
     }

     pkt_list->pkt   = *packet;
     pkt_list->next  = NULL;

     //上锁
     SDL_LockMutex(queue->mutex);

     if (queue->last_pkt == NULL)    //空队
     {
          queue->first_pkt = pkt_list;
     }
     else
     {
         queue->last_pkt->next = pkt_list;
     }

     queue->last_pkt = pkt_list;  //这里queue->last_pkt = queue->last_pkt->next 的意思,但是,处理了更多的情况。
     queue->nb_packets++;
     queue->size += packet->size;
     SDL_CondSignal(queue->cond);      //???

     SDL_UnlockMutex(queue->mutex);

     return 0;
}

/*======================================================================\
* Author     (作者): i.sshe
* Date       (日期): 2016/10/03
* Others     (其他): 出队
\*=======================================================================*/
extern int quit;
int packet_queue_get(PacketQueue *queue, AVPacket *pkt, int block)
{
     AVPacketList   *pkt_list = NULL;
     int            ret = 0;

     SDL_LockMutex(queue->mutex);

     while(1)
     {
          if (quit)
          {
              ret = -1;
              break;
          }

          pkt_list = queue->first_pkt;
          if (pkt_list != NULL)         //队不空,还有数据
          {
              queue->first_pkt = queue->first_pkt->next;    //pkt_list->next
              if (queue->first_pkt == NULL)
              {
                   queue->last_pkt = NULL;
              }

              queue->nb_packets--;
              queue->size -= pkt_list->pkt.size;
              *pkt = pkt_list->pkt;          // 复制给packet。
              av_free(pkt_list);
              ret = 1;
              break;
          }
          else if (block == 0)
          {
               ret = 0;
               break;
          }
          else
          {
              SDL_CondWait(queue->cond, queue->mutex);
          }
     }

     SDL_UnlockMutex(queue->mutex);
     return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • wrap_base.h
#ifndef WRAP_BASE_H_
#define WRAP_BASE_H_

#ifdef __cplusplus
extern "C"{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>

int find_stream_index(AVFormatContext *pformat_ctx, int *video_stream, int *audio_stream);

void get_file_name(char *filename, int argc, char *argv[]);

#ifdef __cplusplus
}
#endif
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • wrap_base.c
#define __STDC_CONSTANT_MACROS      //ffmpeg要求

#ifdef __cplusplus
extern "C"
{
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <SDL2/SDL.h>

#include <assert.h>
#include "wrap_base.h"
#ifdef __cplusplus
}
#endif


/*======================================================================\
* Author     (作者): i.sshe
* Date       (日期): 2016/10/03
* Others     (其他): 成功返回
\*=======================================================================*/
int find_stream_index(AVFormatContext *pformat_ctx, int *video_stream, int *audio_stream)
{
    assert(video_stream != NULL || audio_stream != NULL);

     int i = 0;
     int audio_index = -1;
     int video_index = -1;

     for (i = 0; i < pformat_ctx->nb_streams; i++)
     {
          if (pformat_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
          {
              video_index = i;
          }
          if (pformat_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
          {
              audio_index = i;
          }
     }

     //注意以下两个判断有可能返回-1.
     if (video_stream == NULL)
     {
         *audio_stream = audio_index;
         return *audio_stream;
     }

     if (audio_stream == NULL)
     {
         *video_stream = video_index;
          return *video_stream;
     }

     *video_stream = video_index;
     *audio_stream = audio_index;

     return 0;
}

/*======================================================================\
* Author     (作者): i.sshe
* Date       (日期): 2016/10/03
* Others     (其他): 获取文件名
\*=======================================================================*/
void get_file_name(char *filename, int argc, char *argv[])
{
    if (argc == 2)
    {
        memcpy(filename, argv[1], strlen(argv[1])+1);
    }
    else if (argc > 2)
    {
         fprintf(stderr, "Usage: ./*.out filename\n");
         exit(-1);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

3.2 编译

  • Mackfile(蹩脚的)
CC = g++

SOURCE = *.c 
TARGET = audio_player_v1.2.out
LIBDIR = -L/usr/local/lib 
INCDIR = -I/usr/local/include/ -I../../common/ 
OPTION = -O2 -Wall -g 
LIB_FFMPEG = -lavformat -lavcodec -lavformat -lavutil -lswresample -lswscale
LIB_SDL2 = -lSDL2 -lSDL2main
LIB_OTHER = -lx264 -lx265 -lvpx -lmp3lame -lopus -lfdk-aac -lX11 -lva -lvdpau -lva-drm -lva-x11 -lvorbisenc -lvorbis -ltheoraenc -ltheoradec -ldl -lm -lpthread -lz 

all:
    $(CC) $(SOURCE) -o  $(TARGET) $(LIBDIR) $(INCDIR) $(OPTION) $(LIB_FFMPEG) $(LIB_OTHER) $(LIB_SDL2)
clean:
    rm -f *.out 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.3 运行

./filename.out 
  • 1
  • 1

或者

./filename.out audiofile 
  • 1
  • 1

4. 参考资料

5. 代码下载

posted @ 2017-09-01 17:08  苍月代表我  阅读(2003)  评论(1编辑  收藏  举报