zoukankan      html  css  js  c++  java
  • 关于解决用tutorial7教程中的代码打造一款自己的播放器中的声音噪音问题

    ////////////////////////////////////////////////////////////////////////////////////////////
    对于用FFMPEG2.01和SDL2.01最新的版本来做音频播放器,这篇文章和版本是很有值得参考的价值
    这篇文章解决了我在做简易播放器的时候,用tutorial07的代码的时候,声音播放出现杂音的问题
    出现杂音的问题原因可以从http://blog.csdn.net/leixiaohua1020/article/details/10528443中找到原因,
    因为:
    “新版本中使用了最新版本的FFMPEG类库(2014.5.7)。
    FFMPEG在新版本中的音频解码方面发生了比较大的变化。
    如果将旧版的主程序和新版的类库组合使用的话,会出现听到的都是杂音这一现象。
    经过研究发现,新版中avcodec_decode_audio4()解码后输出的音频采样数据格式为AV_SAMPLE_FMT_FLTP(float, planar)
    而不再是AV_SAMPLE_FMT_S16(signed 16 bits)。因此无法直接使用SDL进行播放。
    最后的解决方法是使用SwrContext对音频采样数据进行转换之后,再进行输出播放,问题就可以得到解决了。”

    /*=======================来自:http://www.cnblogs.com/lidabo/p/3701074.html================================*/

    FFMPEG + SDL音频播放分析
    目录 [hide]

    1 抽象流程:
    2 关键实现:
    2.1 main()函数
    2.2 decode_thread()读取文件信息和音频包
    2.3 stream_component_open():设置音频参数和打开设备
    2.4 audio_callback(): 回调函数,向SDL缓冲区填充数据
    2.5 audio_decode_frame():解码音频
    3 FFMPEG结构体
    3.1 channel_layout_map
    4 FFMPEG宏定义
    4.1 Audio channel convenience macros
    5 SDL宏定义
    5.1 SDL_AudioSpec format
    抽象流程:
    设置SDL的音频参数 —-> 打开声音设备,播放静音 —-> ffmpeg读取音频流中数据放入队列 —-> SDL调用用户设置的函数来获取音频数据 —-> 播放音频

    SDL内部维护了一个buffer来存放解码后的数据,这个buffer中的数据来源是我们注册的回调函数(audio_callback),
    audio_callback调用audio_decode_frame来做具体的音频解码工作,需要引起注意的是:
    从流中读取出的一个音频包(avpacket)可能含有多个音频桢(avframe),所以需要多次调用avcodec_decode_audio4来完成整个包的解码,
    解码出来的数据存放在我们自己的缓冲中(audio_buf2)。SDL每一次回调都会引起数据从audio_buf2拷贝到SDL内部缓冲区,
    当audio_buf2中的数据大于SDL的缓冲区大小时,需要分多次拷贝。

    关键实现:

     1 main()函数
     2 1    int main(int argc, char **argv){
     3 2    SDL_Event event; //SDL事件变量
     4 3    VideoState *is; // 纪录视频及解码器等信息的大结构体
     5 4    is = (VideoState*) av_mallocz(sizeof(VideoState));
     6 5    if(argc < 2){
     7 6      fprintf(stderr, "Usage: play <file>
    ");
     8 7      exit(1);
     9 8    }
    10 9    av_register_all(); //注册所有ffmpeg的解码器
    11 10    /* 初始化SDL,这里只实用了AUDIO,如果有视频,好需要SDL_INIT_VIDEO等等 */
    12 11    if(SDL_Init(SDL_INIT_AUDIO)){
    13 12      fprintf(stderr, "Count not initialize SDL - %s
    ", SDL_GetError());
    14 13      exit(1);
    15 14    }
    16 15    is_strlcpy(is->filename, argv[1], sizeof(is->filename));
    17 16    /* 创建一个SDL线程来做视频解码工作,主线程进入SDL事件循环 */
    18 17    is->parse_tid = SDL_CreateThread(decode_thread, is);
    19 18    if(!is->parse_tid){
    20 19      SDL_WaitEvent(&event);
    21 20      switch(event.type){
    22 21        case FF_QUIT_EVENT:
    23 22        case SDL_QUIT:
    24 23          is->quit = 1;
    25 24          SDL_Quit();
    26 25          exit(0);
    27 26          break;
    28 27        default:
    29 28          break;
    30 29       }
    31 30    }
    32 31    return 0;
    33 32    }


    decode_thread()读取文件信息和音频包:

     1 1    static int decode_thread(void *arg){
     2 2    VideoState *is = (VideoState*)arg;
     3 3    AVFormatContext *ic = NULL;
     4 4    AVPacket pkt1, *packet = &pkt1;
     5 5    int ret, i, audio_index = -1;
     6 6    
     7 7    is->audioStream = -1;
     8 8    global_video_state = is; 
     9 9    /* 使用ffmpeg打开视频,解码器等 常规工作 */
    10 10    if(avFormat_open_input(&ic, is->filename, NULL, NULL) != 0) {
    11 11    fprintf(stderr, "open file error: %s
    ", is->filename);
    12 12    return -1;
    13 13    }
    14 14    is->ic = ic;
    15 15    if(avformat_find_stream_info(ic, NULL) < 0){
    16 16    fprintf(stderr, "find stream info error
    ");
    17 17    return -1;
    18 18    }
    19 19    av_dump_format(ic, 0, is->filename, 0);
    20 20    for(i = 0; i < ic->nb_streams; i++){
    21 21    if(ic->streams[i])->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index == -1){
    22 22    audio_index = i;
    23 23    break;
    24 24    }
    25 25    }
    26 26    if(audio_index >= 0) {
    27 27    /* 所有设置SDL音频流信息的步骤都在这个函数里完成 */
    28 28    stream_component_open(is, audio_index);
    29 29    }
    30 30    if(is->audioStream < 0){
    31 31    fprintf(stderr, "could not open codecs for file: %s
    ", is->filename);
    32 32    goto fail;
    33 33    }
    34 34    /* 读包的主循环, av_read_frame不停的从文件中读取数据包(这里只取音频包)*/
    35 35    for(;;){
    36 36    if(is->quit) break;
    37 37    /* 这里audioq.size是指队列中的所有数据包带的音频数据的总量,并不是包的数量 */
    38 38    if(is->audioq.size > MAX_AUDIO_SIZE){
    39 39    SDL_Delay(10); // 毫秒
    40 40    continue;
    41 41    }
    42 42    ret = av_read_frame(is->ic, packet);
    43 43    if(ret < 0){
    44 44    if(ret == AVERROR_EOF || url_feof(is->ic->pb)) break;
    45 45    if(is->ic->pb && is->ic->pb->error) break;
    46 46    contiue; 
    47 47    } 
    48 48    if(packet->stream_index == is->audioStream){
    49 49    packet_queue_put(&is->audioq, packet);
    50 50    } else{
    51 51    av_free_packet(packet);
    52 52    }
    53 53    }
    54 54    while(!is->quit) SDL_Delay(100);
    55 55    fail: {
    56 56    SDL_Event event;
    57 57    event.type = FF_QUIT_EVENT;
    58 58    event.user.data1 = is;
    59 59    SDL_PushEvent(&event);
    60 60    }
    61 61    return 0;
    62 62    }


    stream_component_open():设置音频参数和打开设备

     1 1    int stream_component_open(videoState *is, int stream_index){
     2 2    AVFormatContext *ic = is->ic;
     3 3    AVCodecContext *codecCtx;
     4 4    AVCodec *codec;
     5 5    /* 在用SDL_OpenAudio()打开音频设备的时候需要这两个参数*/
     6 6    /* wanted_spec是我们期望设置的属性,spec是系统最终接受的参数 */
     7 7    /* 我们需要检查系统接受的参数是否正确 */
     8 8    SDL_AudioSpec wanted_spec, spec;
     9 9    int64_t wanted_channel_layout = 0; // 声道布局(SDL中的具体定义见“FFMPEG结构体”部分) 
    10 10    int wanted_nb_channels; // 声道数
    11 11    /* SDL支持的声道数为 1, 2, 4, 6 */
    12 12    /* 后面我们会使用这个数组来纠正不支持的声道数目 */
    13 13    const int next_nb_channels[] = { 0, 0, 1, 6, 2, 6, 4, 6 }; 
    14 14    
    15 15    if(stream_index < 0 || stream_index >= ic->nb_streams) return -1;
    16 16    codecCtx = ic->streams[stream_index]->codec;
    17 17    wanted_nb_channels = codecCtx->channels;
    18 18    if(!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
    19 19    wanted_channel_layout = av_get_default_channel_lauout(wanted_channel_nb_channels);
    20 20    wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
    21 21    }
    22 22    wanted_spec.channels = av_get_channels_layout_nb_channels(wanted_channel_layout);
    23 23    wanted_spec.freq = codecCtx->sample_rate;
    24 24    if(wanted_spec.freq <= 0 || wanted_spec.channels <=0){
    25 25    fprintf(stderr, "Invaild sample rate or channel count!
    ");
    26 26    return -1;
    27 27    }
    28 28    wanted_spec.format = AUDIO_S16SYS; // 具体含义请查看“SDL宏定义”部分
    29 29    wanted_spec.silence = 0; // 0指示静音
    30 30    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; // 自定义SDL缓冲区大小
    31 31    wanted_spec.callback = audio_callback; // 音频解码的关键回调函数
    32 32    wanted_spec.userdata = is; // 传给上面回调函数的外带数据
    33 33    
    34 34    /* 打开音频设备,这里使用一个while来循环尝试打开不同的声道数(由上面 */
    35 35    /* next_nb_channels数组指定)直到成功打开,或者全部失败 */
    36 36    while(SDL_OpenAudio(&wanted_spec, &spec) < 0){
    37 37    fprintf(stderr, "SDL_OpenAudio(%d channels): %s
    ", wanted_spec.channels, SDL_GetError());
    38 38    wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; // FFMIN()由ffmpeg定义的宏,返回较小的数
    39 39    if(!wanted_spec.channels){
    40 40    fprintf(stderr, "No more channel to try
    ");
    41 41    return -1;
    42 42    }
    43 43    wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
    44 44    }
    45 45    /* 检查实际使用的配置(保存在spec,由SDL_OpenAudio()填充) */
    46 46    if(spec.format != AUDIO_S16SYS){
    47 47    fprintf(stderr, "SDL advised audio format %d is not supported
    ", spec.format);
    48 48    return -1;
    49 49    }
    50 50    if(spec.channels != wanted_spec.channels) {
    51 51    wanted_channel_layout = av_get_default_channel_layout(spec.channels);
    52 52    if(!wanted_channel_layout){
    53 53    fprintf(stderr, "SDL advised channel count %d is not support
    ", spec.channels);
    54 54    return -1;
    55 55    }
    56 56    }
    57 57    /* 把设置好的参数保存到大结构中 */
    58 58    is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
    59 59    is->audio_src_freq = is->audio_tgt_freq = spec.freq;
    60 60    is->audio_src_channel_layout = is->audio_tgt_layout = wanted_channel_layout;
    61 61    is->audio_src_channels = is->audio_tat_channels = spec.channels;
    62 62    
    63 63    codec = avcodec_find_decoder(codecCtx>codec_id);
    64 64    if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)){
    65 65    fprintf(stderr, "Unsupported codec!
    ");
    66 66    return -1;
    67 67    }
    68 68    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; //具体含义请查看“FFMPEG宏定义”部分
    69 69    is->audioStream = stream_index;
    70 70    is->audio_st = ic->streams[stream_index];
    71 71    is->audio_buf_size = 0;
    72 72    is->audio_buf_index = 0;
    73 73    memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
    74 74    packet_queue_init(&is->audioq);
    75 75    SDL_PauseAudio(0); // 开始播放静音
    76 76    }


    audio_callback(): 回调函数,向SDL缓冲区填充数据

      1 void audio_callback(void *userdata, Uint8 *stream, int len)
      2 {
      3     VideoState *is = (VideoState*)userdata;
      4     int len1, audio_data_size;
      5     
      6     /* len是由SDL传入的SDL缓冲区的大小,如果这个缓冲未满,我们就一直往里填充数据 */
      7     while(len > 0){
      8     /* audio_buf_index 和 audio_buf_size 标示我们自己用来放置解码出来的数据的缓冲区,*/
      9     /* 这些数据待copy到SDL缓冲区, 当audio_buf_index >= audio_buf_size的时候意味着我*/
     10     /* 们的缓冲为空,没有数据可供copy,这时候需要调用audio_decode_frame来解码出更
     11     /* 多的桢数据 */
     12     if(is->audio_buf_index >= is->audio_buf_size){
     13         audio_data_size = audio_decode_frame(is);
     14         /* audio_data_size < 0 标示没能解码出数据,我们默认播放静音 */
     15         if(audio_data_size < 0)
     16         {
     17             is->audio_buf_size = 1024;
     18             /* 清零,静音 */
     19             memset(is->audio_buf, 0, is->audio_buf_size);
     20         } 
     21         else
     22         {
     23             is->audio_buf_size = audio_data_size;
     24         }
     25         is->audio_buf_index = 0;
     26     }
     27     /* 查看stream可用空间,决定一次copy多少数据,剩下的下次继续copy */
     28     len1 = is->audio_buf_size - is->audio_buf_index;
     29     if(len1 > len) len1 = len;
     30     
     31     memcpy(stream, (uint8_t*)is->audio_buf + is->audio_buf_index, len1);
     32     len -= len1;
     33     stream += len1;
     34     is->audio_buf_index += len1;
     35     }
     36 }
     37 
     38  
     39 
     40 audio_decode_frame():解码音频
     41     int audio_decode_frame(VideoState *is)
     42     {
     43         int len1, len2, decoded_data_size;
     44         AVPacket *pkt = &is->audio_pkt;
     45         int got_frame = 0;
     46         int64_t dec_channel_layout;
     47         int wanted_nb_samples, resampled_data_size;
     48     
     49         for(;;)
     50         {
     51         while(is->audio_pkt_size > 0)
     52         {
     53             if(!is->audio_frame)
     54             {
     55                 if(!(is->audio_frame = avacodec_alloc_frame()))
     56                 {
     57                 return AVERROR(ENOMEM);
     58                 }
     59             } 
     60             else
     61                 avcodec_get_frame_defaults(is->audio_frame);
     62         
     63             len1 = avcodec_decode_audio4(is->audio_st_codec, is->audio_frame, got_frame, pkt);
     64             /* 解码错误,跳过整个包 */
     65             if(len1 < 0)
     66             {
     67                 is->audio_pkt_size = 0;
     68                 break;
     69             }
     70             is->audio_pkt_data += len1;
     71             is->audio_pkt_size -= len1;
     72             if(!got_frame) continue;
     73             /* 计算解码出来的桢需要的缓冲大小 */
     74             decoded_data_size = av_samples_get_buffer_size(NULL,
     75             is->audio_frame_channels,
     76             is->audio_frame_nb_samples,
     77             is->audio_frame_format, 1);
     78             dec_channel_layout = (is->audio_frame->channel_layout && is->audio_frame->channels== av_get_channel_layout_nb_channels(is->audio_frame->channel_layout))
     79                                 ? is->audio_frame->channel_layout : av_get_default_channel_layout(is->audio_frame->channels); 
     80             wanted_nb_samples = is->audio_frame->nb_samples;
     81             if (is->audio_frame->format != is->audio_src_fmt || 
     82             dec_channel_layout != is->audio_src_channel_layout ||
     83             is->audio_frame->sample_rate != is->audio_src_freq || 
     84             (wanted_nb_samples != is->audio_frame->nb_samples && !is->swr_ctx)) 
     85             {
     86                 if (is->swr_ctx) 
     87                     swr_free(&is->swr_ctx);
     88                 is->swr_ctx = swr_alloc_set_opts(NULL,
     89                                                 is->audio_tgt_channel_layout,
     90                                                 is->audio_tgt_fmt,
     91                                                 is->audio_tgt_freq,
     92                                                 dec_channel_layout,
     93                                                 is->audio_frame->format,
     94                                                 is->audio_frame->sample_rate,
     95                                                 0, NULL);
     96                 if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) 
     97                 {
     98                     fprintf(stderr, "swr_init() failed
    ");
     99                     break;
    100                 }
    101                 is->audio_src_channel_layout = dec_channel_layout;
    102                 is->audio_src_channels = is->audio_st->codec->channels;
    103                 is->audio_src_freq = is->audio_st->codec->sample_rate;
    104                 is->audio_src_fmt = is->audio_st->codec->sample_fmt;
    105             }
    106             /* 这里我们可以对采样数进行调整,增加或者减少,一般可以用来做声画同步 */
    107             if (is->swr_ctx) 
    108             {
    109                 const uint8_t **in = (const uint8_t **)is->audio_frame->extended_data;
    110                 uint8_t *out[] = { is->audio_buf2 };
    111                 if (wanted_nb_samples != is->audio_frame->nb_samples) 
    112                 {
    113                     if(swr_set_compensation(is->swr_ctx, 
    114                                             (wanted_nb_samples - is->audio_frame->nb_samples)*is->audio_tgt_freq/is->audio_frame->sample_rate,
    115                                             wanted_nb_samples * is->audio_tgt_freq/is->audio_frame->sample_rate) < 0) 
    116                     {
    117                         fprintf(stderr, "swr_set_compensation() failed
    ");
    118                         break;
    119                     }
    120                 }
    121                 len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2)/is->audio_tgt_channels/av_get_bytes_per_sample(is->audio_tgt_fmt), 
    122                                     in, is->audio_frame->nb_samples);
    123                 if (len2 < 0) 
    124                 {
    125                     fprintf(stderr, "swr_convert() failed
    ");
    126                     break;
    127                 }
    128                 if(len2 == sizeof(is->audio_buf2)/is->audio_tgt_channels/av_get_bytes_per_sample(is->audio_tgt_fmt)) 
    129                 {
    130                     fprintf(stderr, "warning: audio buffer is probably too small
    ");
    131                     swr_init(is->swr_ctx);
    132                 }
    133                 is->audio_buf = is->audio_buf2;
    134                 resampled_data_size = len2*is->audio_tgt_channels*av_get_bytes_per_sample(is->audio_tgt_fmt);
    135             } else {
    136                 resampled_data_size = decoded_data_size;
    137                 is->audio_buf = is->audio_frame->data[0];
    138             }
    139             /* 返回得到的数据 */
    140             return resampled_data_size;
    141         }
    142         if (pkt->data) av_free_packet(pkt);
    143         memset(pkt, 0, sizeof(*pkt));
    144         if (is->quit) return -1;
    145         if (packet_queue_get(&is->audioq, pkt, 1) < 0) return -1;
    146         is->audio_pkt_data = pkt->data;
    147         is->audio_pkt_size = pkt->size;
    148     
    149         }
    150     }

    FFMPEG结构体
    channel_layout_map
    1 static const struct {
    2 const char *name;
    3 int nb_channels;
    4 uint64_t layout;
    5 } channel_layout_map[] = {
    6 { "mono", 1, AV_CH_LAYOUT_MONO },
    7 { "stereo", 2, AV_CH_LAYOUT_STEREO },
    8 { "2.1", 3, AV_CH_LAYOUT_2POINT1 },
    9 { "3.0", 3, AV_CH_LAYOUT_SURROUND },
    10 { "3.0(back)", 3, AV_CH_LAYOUT_2_1 },
    11 { "4.0", 4, AV_CH_LAYOUT_4POINT0 },
    12 { "quad", 4, AV_CH_LAYOUT_QUAD },
    13 { "quad(side)", 4, AV_CH_LAYOUT_2_2 },
    14 { "3.1", 4, AV_CH_LAYOUT_3POINT1 },
    15 { "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
    16 { "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 },
    17 { "4.1", 5, AV_CH_LAYOUT_4POINT1 },
    18 { "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
    19 { "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 },
    20 { "6.0", 6, AV_CH_LAYOUT_6POINT0 },
    21 { "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT },
    22 { "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL },
    23 { "6.1", 7, AV_CH_LAYOUT_6POINT1 },
    24 { "6.1", 7, AV_CH_LAYOUT_6POINT1_BACK },
    25 { "6.1(front)", 7, AV_CH_LAYOUT_6POINT1_FRONT },
    26 { "7.0", 7, AV_CH_LAYOUT_7POINT0 },
    27 { "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
    28 { "7.1", 8, AV_CH_LAYOUT_7POINT1 },
    29 { "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
    30 { "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL },
    31 { "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, },
    32 };


    FFMPEG宏定义
    Audio channel convenience macros
    1 #define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER)
    2 #define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
    3 #define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY)
    4 #define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER)
    5 #define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)
    6 #define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY)
    7 #define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER)
    8 #define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY)
    9 #define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
    10 #define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
    11 #define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
    12 #define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY)
    13 #define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
    14 #define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY)
    15 #define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER)
    16 #define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
    17 #define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER)
    18 #define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER)
    19 #define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER)
    20 #define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY)
    21 #define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
    22 #define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
    23 #define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
    24 #define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
    25 #define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
    26 #define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT)
    27 #define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT)


    SDL宏定义
    SDL_AudioSpec format
    1 AUDIO_U8 Unsigned 8-bit samples
    2 AUDIO_S8 Signed 8-bit samples
    3 AUDIO_U16LSB Unsigned 16-bit samples, in little-endian byte order
    4 AUDIO_S16LSB Signed 16-bit samples, in little-endian byte order
    5 AUDIO_U16MSB Unsigned 16-bit samples, in big-endian byte order
    6 AUDIO_S16MSB Signed 16-bit samples, in big-endian byte order
    7 AUDIO_U16 same as AUDIO_U16LSB (for backwards compatability probably)
    8 AUDIO_S16 same as AUDIO_S16LSB (for backwards compatability probably)
    9 AUDIO_U16SYS Unsigned 16-bit samples, in system byte order
    10 AUDIO_S16SYS Signed 16-bit samples, in system byte order


    git clone https://github.com/lnmcc/musicPlayer.git

  • 相关阅读:
    函数总结
    python之内置函数,匿名函数
    列表推导式 生成器表达式
    迭代器和生成器函数
    最近练习题
    python----------闭包 、装饰器
    python的逻辑运算符
    python------函数嵌套及作用域链
    python ---------函数
    如何实现负载均衡
  • 原文地址:https://www.cnblogs.com/lihaiping/p/4027705.html
Copyright © 2011-2022 走看看