一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——解码篇:(二)用ffmpeg解码音频
2016-03-17 10:15 Ansersion 阅读(1695) 评论(0) 编辑 收藏 举报其实这篇的内容和(一)用ffmpeg解码视频基本是一样的,重点还是给ffmpeg指定callback函数,而这个函数是从RTSP服务端那里获取音频数据的。
这里,解码音频的示例代码量之所以比解码视频的略微复杂,主要是因为ffmpeg解码音频时要比解码视频要复杂一点,具体可以参见ffmpeg解码音频示例以及官网示例代码。
具体内容将不再赘述,源码如下:
1 extern "C" 2 { 3 #include <libavcodec/avcodec.h> 4 #include <libavformat/avformat.h> 5 #include <libavformat/avio.h> 6 #include <libswscale/swscale.h> 7 #include <libswresample/swresample.h> 8 } 9 10 #include <SDL.h> 11 #include <SDL_thread.h> 12 13 #ifdef __MINGW32__ 14 #undef main /* Prevents SDL from overriding main() */ 15 #endif 16 17 #include <stdio.h> 18 #include <assert.h> 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 23 24 // compatibility with newer API 25 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 26 #define av_frame_alloc avcodec_alloc_frame 27 #define av_frame_free avcodec_free_frame 28 #endif 29 30 #define SDL_AUDIO_BUFFER_SIZE 1024 31 #define MAX_AUDIO_FRAME_SIZE 192000 32 33 #include <signal.h> 34 #include "rtspClient.h" 35 #include <iostream> 36 #include <string> 37 38 using std::cout; 39 using std::endl; 40 41 int rtspClientRequest(RtspClient * Client, string url); 42 int fill_iobuffer(void * opaque, uint8_t * buf, int bufsize); 43 44 typedef struct AudioParams { 45 int freq; 46 int channels; 47 int64_t channel_layout; 48 enum AVSampleFormat fmt; 49 int frame_size; 50 int bytes_per_sec; 51 } AudioParams; 52 int sample_rate, nb_channels; 53 int64_t channel_layout; 54 AudioParams audio_hw_params_tgt; 55 AudioParams audio_hw_params_src; 56 57 int resample(AVFrame * af, uint8_t * audio_buf, int * audio_buf_size); 58 59 struct SwrContext * swr_ctx = NULL; 60 61 int resample(AVFrame * af, uint8_t * audio_buf, int * audio_buf_size) 62 { 63 int data_size = 0; 64 int resampled_data_size = 0; 65 int64_t dec_channel_layout; 66 data_size = av_samples_get_buffer_size(NULL, 67 av_frame_get_channels(af), 68 af->nb_samples, 69 (AVSampleFormat)af->format, 70 1); 71 72 dec_channel_layout = 73 (af->channel_layout && av_frame_get_channels(af) == av_get_channel_layout_nb_channels(af->channel_layout)) ? 74 af->channel_layout : av_get_default_channel_layout(av_frame_get_channels(af)); 75 if( af->format != audio_hw_params_src.fmt || 76 af->sample_rate != audio_hw_params_src.freq || 77 dec_channel_layout != audio_hw_params_src.channel_layout || 78 !swr_ctx) { 79 swr_free(&swr_ctx); 80 swr_ctx = swr_alloc_set_opts(NULL, 81 audio_hw_params_tgt.channel_layout, (AVSampleFormat)audio_hw_params_tgt.fmt, audio_hw_params_tgt.freq, 82 dec_channel_layout, (AVSampleFormat)af->format, af->sample_rate, 83 0, NULL); 84 if (!swr_ctx || swr_init(swr_ctx) < 0) { 85 av_log(NULL, AV_LOG_ERROR, 86 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", 87 af->sample_rate, av_get_sample_fmt_name((AVSampleFormat)af->format), av_frame_get_channels(af), 88 audio_hw_params_tgt.freq, av_get_sample_fmt_name(audio_hw_params_tgt.fmt), audio_hw_params_tgt.channels); 89 swr_free(&swr_ctx); 90 return -1; 91 } 92 printf("swr_init\n"); 93 audio_hw_params_src.channels = av_frame_get_channels(af); 94 audio_hw_params_src.fmt = (AVSampleFormat)af->format; 95 audio_hw_params_src.freq = af->sample_rate; 96 } 97 98 if (swr_ctx) { 99 const uint8_t **in = (const uint8_t **)af->extended_data; 100 uint8_t **out = &audio_buf; 101 int out_count = (int64_t)af->nb_samples * audio_hw_params_tgt.freq / af->sample_rate + 256; 102 int out_size = av_samples_get_buffer_size(NULL, audio_hw_params_tgt.channels, out_count, audio_hw_params_tgt.fmt, 0); 103 int len2; 104 if (out_size < 0) { 105 av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n"); 106 return -1; 107 } 108 av_fast_malloc(&audio_buf, (unsigned int*)audio_buf_size, out_size); 109 if (!audio_buf) 110 return AVERROR(ENOMEM); 111 len2 = swr_convert(swr_ctx, out, out_count, in, af->nb_samples); 112 if (len2 < 0) { 113 av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n"); 114 return -1; 115 } 116 if (len2 == out_count) { 117 av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n"); 118 if (swr_init(swr_ctx) < 0) 119 swr_free(&swr_ctx); 120 } 121 resampled_data_size = len2 * audio_hw_params_tgt.channels * av_get_bytes_per_sample(audio_hw_params_tgt.fmt); 122 } else { 123 audio_buf = af->data[0]; 124 resampled_data_size = data_size; 125 } 126 127 return resampled_data_size; 128 } 129 130 static void sigterm_handler(int sig) 131 { 132 exit(123); 133 } 134 135 typedef struct PacketQueue { 136 AVPacketList *first_pkt, *last_pkt; 137 int nb_packets; 138 int size; 139 SDL_mutex *mutex; 140 SDL_cond *cond; 141 } PacketQueue; 142 143 PacketQueue audioq; 144 145 int quit = 0; 146 147 void packet_queue_init(PacketQueue *q) { 148 memset(q, 0, sizeof(PacketQueue)); 149 q->mutex = SDL_CreateMutex(); 150 q->cond = SDL_CreateCond(); 151 } 152 153 int packet_queue_put(PacketQueue *q, AVPacket *pkt) { 154 155 AVPacketList *pkt1; 156 if(av_dup_packet(pkt) < 0) { 157 return -1; 158 } 159 pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList)); 160 if (!pkt1) 161 return -1; 162 pkt1->pkt = *pkt; 163 pkt1->next = NULL; 164 165 166 SDL_LockMutex(q->mutex); 167 168 if (!q->last_pkt) 169 q->first_pkt = pkt1; 170 else 171 q->last_pkt->next = pkt1; 172 q->last_pkt = pkt1; 173 q->nb_packets++; 174 q->size += pkt1->pkt.size; 175 SDL_CondSignal(q->cond); 176 177 SDL_UnlockMutex(q->mutex); 178 return 0; 179 } 180 181 int packet_queue_put_nullpacket(PacketQueue *q, int stream_index) 182 { 183 AVPacket pkt1, *pkt = &pkt1; 184 av_init_packet(pkt); 185 pkt->data = NULL; 186 pkt->size = 0; 187 pkt->stream_index = stream_index; 188 return packet_queue_put(q, pkt); 189 } 190 191 static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) 192 { 193 AVPacketList *pkt1; 194 int ret; 195 196 SDL_LockMutex(q->mutex); 197 198 for(;;) { 199 200 if(quit) { 201 ret = -1; 202 break; 203 } 204 205 pkt1 = q->first_pkt; 206 if (pkt1) { 207 q->first_pkt = pkt1->next; 208 if (!q->first_pkt) 209 q->last_pkt = NULL; 210 q->nb_packets--; 211 q->size -= pkt1->pkt.size; 212 *pkt = pkt1->pkt; 213 av_free(pkt1); 214 ret = 1; 215 break; 216 } else if (!block) { 217 ret = 0; 218 break; 219 } else { 220 SDL_CondWait(q->cond, q->mutex); 221 } 222 } 223 SDL_UnlockMutex(q->mutex); 224 return ret; 225 } 226 227 AVFrame frame; 228 int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size) { 229 230 static AVPacket pkt; 231 static uint8_t *audio_pkt_data = NULL; 232 static int audio_pkt_size = 0; 233 234 int len1, data_size = 0; 235 236 for(;;) { 237 while(audio_pkt_size > 0) { 238 int got_frame = 0; 239 len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt); 240 if(len1 < 0) { 241 /* if error, skip frame */ 242 audio_pkt_size = 0; 243 break; 244 } 245 audio_pkt_data += len1; 246 audio_pkt_size -= len1; 247 data_size = 0; 248 if(got_frame) { 249 data_size = resample(&frame, audio_buf, &buf_size); 250 // data_size = av_samples_get_buffer_size(NULL, 251 // aCodecCtx->channels, 252 // frame.nb_samples, 253 // aCodecCtx->sample_fmt, 254 // 1); 255 assert(data_size <= buf_size); 256 // memcpy(audio_buf, frame.data[0], data_size); 257 } 258 if(data_size <= 0) { 259 /* No data yet, get more frames */ 260 continue; 261 } 262 // memcpy(audio_buf, frame.data[0], data_size); 263 264 /* We have data, return it and come back for more later */ 265 return data_size; 266 } 267 if(pkt.data) 268 av_free_packet(&pkt); 269 270 if(quit) { 271 return -1; 272 } 273 274 if(packet_queue_get(&audioq, &pkt, 1) < 0) { 275 return -1; 276 } 277 audio_pkt_data = pkt.data; 278 audio_pkt_size = pkt.size; 279 } 280 } 281 282 void audio_callback(void *userdata, Uint8 *stream, int len) { 283 284 AVCodecContext *aCodecCtx = (AVCodecContext *)userdata; 285 int len1, audio_size; 286 287 static uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2]; 288 static unsigned int audio_buf_size = 0; 289 static unsigned int audio_buf_index = 0; 290 291 while(len > 0) { 292 if(audio_buf_index >= audio_buf_size) { 293 /* We have already sent all our data; get more */ 294 audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf)); 295 if(audio_size < 0) { 296 /* If error, output silence */ 297 audio_buf_size = 1024; // arbitrary? 298 memset(audio_buf, 0, audio_buf_size); 299 } else { 300 audio_buf_size = audio_size; 301 } 302 audio_buf_index = 0; 303 } 304 len1 = audio_buf_size - audio_buf_index; 305 if(len1 > len) 306 len1 = len; 307 memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1); 308 len -= len1; 309 stream += len1; 310 audio_buf_index += len1; 311 } 312 } 313 314 int main(int argc, char *argv[]) { 315 316 AVFormatContext *pFormatCtx = NULL; 317 int i, audioStream; 318 AVPacket packet; 319 320 AVCodecContext *aCodecCtxOrig = NULL; 321 AVCodecContext *aCodecCtx = NULL; 322 AVCodec *aCodec = NULL; 323 324 SDL_Event event; 325 SDL_AudioSpec wanted_spec, spec; 326 327 AVInputFormat *piFmt = NULL; 328 RtspClient Client; 329 330 signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */ 331 signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */ 332 333 if(argc != 2) { 334 cout << "Usage: " << argv[0] << " <URL>" << endl; 335 cout << "For example: " << endl; 336 cout << argv[0] << " rtsp://127.0.0.1/ansersion" << endl; 337 return 1; 338 } 339 rtspClientRequest(&Client, argv[1]); 340 // Register all formats and codecs 341 av_register_all(); 342 343 if(SDL_Init(SDL_INIT_AUDIO)) { 344 fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); 345 exit(1); 346 } 347 348 // // Open video file 349 // if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0) 350 // return -1; // Couldn't open file 351 352 pFormatCtx = NULL; 353 pFormatCtx = avformat_alloc_context(); 354 unsigned char * iobuffer = (unsigned char *)av_malloc(32768); 355 AVIOContext * avio = avio_alloc_context(iobuffer, 32768, 0, &Client, fill_iobuffer, NULL, NULL); 356 pFormatCtx->pb = avio; 357 358 if(!avio) { 359 printf("avio_alloc_context error!!!\n"); 360 return -1; 361 } 362 363 if(av_probe_input_buffer(avio, &piFmt, "", NULL, 0, 0) < 0) { 364 printf("av_probe_input_buffer error!\n"); 365 return -1; 366 } else { 367 printf("probe success\n"); 368 printf("format: %s[%s]\n", piFmt->name, piFmt->long_name); 369 } 370 371 int err = avformat_open_input(&pFormatCtx, "nothing", NULL, NULL); 372 if(err) { 373 printf("avformat_open_input error: %d\n", err); 374 return -1; 375 } 376 // Retrieve stream information 377 if(avformat_find_stream_info(pFormatCtx, NULL)<0) 378 return -1; // Couldn't find stream information 379 380 // Dump information about file onto standard error 381 // av_dump_format(pFormatCtx, 0, argv[1], 0); 382 av_dump_format(pFormatCtx, 0, "", 0); 383 384 // Find the first video stream 385 audioStream=-1; 386 for(i=0; i<pFormatCtx->nb_streams; i++) { 387 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && 388 audioStream < 0) { 389 audioStream=i; 390 } 391 } 392 // if(videoStream==-1) 393 // return -1; // Didn't find a video stream 394 if(audioStream==-1) 395 return -1; 396 397 aCodecCtxOrig=pFormatCtx->streams[audioStream]->codec; 398 aCodec = avcodec_find_decoder(aCodecCtxOrig->codec_id); 399 if(!aCodec) { 400 fprintf(stderr, "Unsupported codec!\n"); 401 return -1; 402 } 403 404 // Copy context 405 aCodecCtx = avcodec_alloc_context3(aCodec); 406 if(avcodec_copy_context(aCodecCtx, aCodecCtxOrig) != 0) { 407 fprintf(stderr, "Couldn't copy codec context"); 408 return -1; // Error copying codec context 409 } 410 411 avcodec_open2(aCodecCtx, aCodec, NULL); 412 413 sample_rate = aCodecCtx->sample_rate; 414 nb_channels = aCodecCtx->channels; 415 channel_layout = aCodecCtx->channel_layout; 416 417 // printf("channel_layout=%" PRId64 "\n", channel_layout); 418 printf("channel_layout=%lld\n", channel_layout); 419 printf("nb_channels=%d\n", nb_channels); 420 printf("freq=%d\n", sample_rate); 421 422 if (!channel_layout || nb_channels != av_get_channel_layout_nb_channels(channel_layout)) { 423 channel_layout = av_get_default_channel_layout(nb_channels); 424 channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX; 425 printf("correction\n"); 426 } 427 428 // Set audio settings from codec info 429 wanted_spec.freq = sample_rate; 430 wanted_spec.format = AUDIO_S16SYS; 431 wanted_spec.channels = nb_channels; 432 wanted_spec.silence = 0; 433 wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; 434 wanted_spec.callback = audio_callback; 435 wanted_spec.userdata = aCodecCtx; 436 437 if(SDL_OpenAudio(&wanted_spec, &spec) < 0) { 438 fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); 439 return -1; 440 } 441 printf("freq: %d\tchannels: %d\n", spec.freq, spec.channels); 442 443 audio_hw_params_tgt.fmt = AV_SAMPLE_FMT_S16; 444 audio_hw_params_tgt.freq = spec.freq; 445 audio_hw_params_tgt.channel_layout = channel_layout; 446 audio_hw_params_tgt.channels = spec.channels; 447 audio_hw_params_tgt.frame_size = av_samples_get_buffer_size(NULL, audio_hw_params_tgt.channels, 1, audio_hw_params_tgt.fmt, 1); 448 audio_hw_params_tgt.bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params_tgt.channels, audio_hw_params_tgt.freq, audio_hw_params_tgt.fmt, 1); 449 if (audio_hw_params_tgt.bytes_per_sec <= 0 || audio_hw_params_tgt.frame_size <= 0) { 450 printf("size error\n"); 451 return -1; 452 } 453 audio_hw_params_src = audio_hw_params_tgt; 454 455 // audio_st = pFormatCtx->streams[index] 456 packet_queue_init(&audioq); 457 SDL_PauseAudio(0); 458 459 // Read frames and save first five frames to disk 460 i=0; 461 int ret = 1; 462 // while(av_read_frame(pFormatCtx, &packet)>=0) { 463 while(ret >= 0) { 464 ret = av_read_frame(pFormatCtx, &packet); 465 466 if(ret < 0) { 467 /* av_read_frame may get error when RTP data are blocked due to the network busy */ 468 if(ret == AVERROR_EOF || avio_feof(pFormatCtx->pb)) { 469 packet_queue_put_nullpacket(&audioq, audioStream); 470 printf("continue ret=%d\n", ret); 471 ret = 0; 472 continue; 473 } 474 printf("ret=%d\n", ret); 475 break; 476 } 477 printf("av_read_frame\n"); 478 if(packet.stream_index==audioStream) { 479 packet_queue_put(&audioq, &packet); 480 } else { 481 av_free_packet(&packet); 482 } 483 // Free the packet that was allocated by av_read_frame 484 SDL_PollEvent(&event); 485 switch(event.type) { 486 case SDL_QUIT: 487 printf("SDL_QUIT\n"); 488 quit = 1; 489 SDL_Quit(); 490 exit(0); 491 break; 492 default: 493 printf("SDL_Default\n"); 494 break; 495 } 496 497 } 498 499 while(1) SDL_Delay(1000); 500 501 // Close the codecs 502 avcodec_close(aCodecCtxOrig); 503 avcodec_close(aCodecCtx); 504 505 // Close the video file 506 avformat_close_input(&pFormatCtx); 507 508 return 0; 509 } 510 511 int rtspClientRequest(RtspClient * Client, string url) 512 { 513 if(!Client) return -1; 514 515 // cout << "Start play " << url << endl; 516 string RtspUri(url); 517 // string RtspUri("rtsp://192.168.81.145/ansersion"); 518 519 /* Set up rtsp server resource URI */ 520 Client->SetURI(RtspUri); 521 522 /* Send DESCRIBE command to server */ 523 Client->DoDESCRIBE(); 524 525 /* Parse SDP message after sending DESCRIBE command */ 526 Client->ParseSDP(); 527 528 /* Send SETUP command to set up all 'audio' and 'video' 529 * sessions which SDP refers. */ 530 Client->DoSETUP(); 531 532 /* Send PLAY command to play only 'video' sessions.*/ 533 Client->DoPLAY("audio"); 534 535 return 0; 536 } 537 538 int fill_iobuffer(void * opaque, uint8_t * buf, int bufsize) { 539 size_t size = 0; 540 if(!opaque) return -1; 541 RtspClient * Client = (RtspClient *)opaque; 542 if(!Client->GetMediaData("audio", buf, &size, bufsize)) size = 0; 543 printf("fill_iobuffer size: %u\n", size); 544 return size; 545 }
注:
1, 兼容myRtspClient-1.2.1及以上版本,且仅支持接收mp2,mp3音频;
2, 音频解码原理可参见:http://www.cnblogs.com/ansersion/p/5265033.html;
3, 示例源码编译需要SDL和ffmpeg,具体可参见解码视频的附录二;
4, 博主编译环境为 x86_64位ubuntu 16.04,以供参考。
编译、配置和运行同上一篇:用ffmpeg解码视频