ffmpeg 實現RTSP/RTMP 從伺服器拉音視訊流,儲存為h264和AAC
阿新 • • 發佈:2018-12-22
int my_av_bsf_filter(const AVBitStreamFilter *filter, AVPacket *pPacket, const AVCodecParameters *src) { int ret; AVBSFContext *ctx = NULL; if (!filter) return 0; ret = av_bsf_alloc(filter, &ctx); if (ret < 0) return ret; ret = avcodec_parameters_copy(ctx->par_in, src); if (ret < 0) return ret; ret = av_bsf_init(ctx); if (ret < 0) return ret; AVPacket pkt = { 0 }; pkt.data = pPacket->data; pkt.size = pPacket->size; ret = av_bsf_send_packet(ctx, &pkt); if (ret < 0) return ret; ret = av_bsf_receive_packet(ctx, &pkt); if (pkt.data == pPacket->data)//額外處理裸流檔案 標準格式 不用往下面走 因為pkt.data沒有新的引用。 { uint8_t *poutbuf = (uint8_t*)av_malloc(pkt.size); if (!poutbuf) { av_packet_unref(&pkt); return -1; } memcpy(poutbuf, pkt.data, pkt.size); av_packet_unref(pPacket); pPacket->data = poutbuf; pPacket->size = pkt.size; av_packet_unref(&pkt); av_bsf_free(&ctx); return 1; //av_packet_unref(pPacket); } if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return 0; else if (ret < 0) return ret; // uint8_t **poutbuf = &(pPacket->data); // int *poutbuf_size = &(pPacket->size); uint8_t *poutbuf = (uint8_t*)av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); if (!poutbuf) { av_packet_unref(&pkt); return AVERROR(ENOMEM); } int poutbuf_size = pkt.size; memcpy(poutbuf, pkt.data, pkt.size); pPacket->data = poutbuf; pPacket->size = poutbuf_size; av_packet_unref(&pkt); /* drain all the remaining packets we cannot return */ while (ret >= 0) { ret = av_bsf_receive_packet(ctx, &pkt); av_packet_unref(&pkt); } av_bsf_free(&ctx); return 1; }
int main(){ AVFormatContext *pFormatCtx; int i, videoindex,audioindex; AVPacket *packet; int ret, got_picture; struct SwsContext *img_convert_ctx; //下面是公共的RTSP測試地址 // char filepath[] = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; //動畫 char filepath[] = "rtmp://live.hkstv.hk.lxdns.com/live/hks";//香港衛視 av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); //AVDictionary* options = NULL; //av_dict_set(&options, "timeout", "10000000", 0); if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)////開啟網路流或檔案流 { printf("Couldn't open input stream.\n"); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream information.\n"); return -1; } videoindex = -1; audioindex = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (videoindex != -1) { continue; } videoindex = i; } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (audioindex != -1) { continue; } audioindex = i; } else { break; } } if (videoindex == -1) { printf("Didn't find a video stream.\n"); return -1; } packet = (AVPacket *)av_malloc(sizeof(AVPacket)); FILE *fpSave; FILE *fpAAcSave; if ((fpSave = fopen("geth264.h264", "wb")) == NULL) //h264儲存的檔名 return 0; if ((fpAAcSave = fopen("gethAAc.aac", "wb")) == NULL) //h264儲存的檔名 return 0; char *padts = (char *)malloc(sizeof(char) * 7); int profile = 2; //AAC LC int freqIdx = 4; //44.1KHz int chanCfg = 2; padts[0] = (char)0xFF; // 11111111 = syncword padts[1] = (char)0xF1; // 1111 1 00 1 = syncword MPEG-2 Layer CRC padts[2] = (char)(((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2)); padts[6] = (char)0xFC; const AVBitStreamFilter *pavBitStFilter = av_bsf_get_by_name("h264_mp4toannexb"); for (;;) { //------------------------------ if (av_read_frame(pFormatCtx, packet) >= 0) { if (packet->stream_index == videoindex) { if (my_av_bsf_filter(pavBitStFilter, packet, pFormatCtx->streams[videoindex]->codecpar) != 1)// 新增pps sps(RTMP需要) { /*len = 0;*/ return false; } fwrite(packet->data, 1, packet->size, fpSave);//寫資料到檔案中 } else if (packet->stream_index == audioindex)// RTMP需要增加AAC的ADTS頭(RTSP不用) { padts[3] = (char)(((chanCfg & 3) << 6) + ((7 + packet->size) >> 11));// 增加ADTS頭 padts[4] = (char)(((7 + packet->size) & 0x7FF) >> 3); padts[5] = (char)((((7 + packet->size) & 7) << 5) + 0x1F); fwrite(padts, 7, 1, fpAAcSave); fwrite(packet->data, 1, packet->size, fpAAcSave);//寫資料到檔案中 } av_free_packet(packet); } } avformat_close_input(&pFormatCtx); return 0; }