網路視訊流 -- ffmpeg 視訊編碼
阿新 • • 發佈:2020-12-12
ffmpeg 作為通用,好用,耐用的視訊處理開源庫,是大多數視訊開發者的唯一選擇,因為沒錢,我也只能用這個。。
使用FFmpeg-4.3.1,DLL版本如上,由於呼叫軟體相容性問題,採用64位版本,直接上程式碼了:
DWORD WINAPI H264CoderFunc(LPVOID pParam) { MSG msg; unsigned char* p; AVCodecContext* pCodecCtx = 0; AVCodec* pCodec; int in_w, in_h, got_picture, ret; AVPacket pkt; uint8_t* picture_buf; AVFrame* pFrame = 0; int picture_size; struct SwsContext* img_convert_ctx; AVDictionary* param = 0; // avcodec_register_all();新版本不需要初始化這個了 // avformat_network_init(); //查詢h264編碼器 pCodec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!pCodec) { goto o_Terminate_Coder_Thread; } pCodecCtx = avcodec_alloc_context3(pCodec); pCodecCtx->codec_id = AV_CODEC_ID_H264; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; pCodecCtx->width = pInf->width; pCodecCtx->height = pInf->height; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = pInf->frame_rate;//幀率 pCodecCtx->bit_rate = 5*1024 * 1024; pCodecCtx->bit_rate_tolerance = 5 * 1024 * 1024; pCodecCtx->rc_min_rate = 5 * 1024 * 1024; pCodecCtx->rc_max_rate = 5 * 1024 * 1024; pCodecCtx->bit_rate_tolerance = 5 * 1024 * 1024; pCodecCtx->rc_buffer_size = 5 * 1024 * 1024; pCodecCtx->rc_initial_buffer_occupancy = pCodecCtx->rc_buffer_size * 3 / 4; pCodecCtx->gop_size = pInf->gop; if (pCodecCtx->flags & AVFMT_GLOBALHEADER) pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //H.264 av_dict_set(¶m, "preset", "superfast", 0); av_dict_set(¶m, "tune", "zerolatency", 0); //實現實時編碼 av_dict_set(¶m, "profile", "main", 0); if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) { printf("Failed to open video encoder1! 編碼器開啟失敗!\n"); goto o_Terminate_Coder_Thread; } pFrame = av_frame_alloc(); if (!pFrame) { fprintf(stderr, "Could not allocate video frame\n"); goto o_Terminate_Coder_Thread; } //AVFrame 記憶體獲取與老版本不同,已修改 picture_size = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1); picture_buf = (uint8_t*)av_mallocz(picture_size); av_image_fill_arrays(pFrame->data, pFrame->linesize, picture_buf, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; pFrame->format = pCodecCtx->pix_fmt; while (GetMessage(&msg, NULL, 0, 0)) { p = (unsigned char*)msg.wParam;//由於是實時資料,採用message機制更容易處理 //將灰度資料轉化為YUV420,要不然無法壓縮 memcpy(pFrame->data[0], p, pCodecCtx->width * pCodecCtx->height); memset(pFrame->data[1], 128, pCodecCtx->width * pCodecCtx->height / 4); memset(pFrame->data[2], 128, pCodecCtx->width * pCodecCtx->height / 4); pkt.data = NULL; pkt.size = 0; av_init_packet(&pkt); //新版本的編碼函式分成了兩部分,已修改 //int iRet = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture); int iRet = avcodec_send_frame(pCodecCtx, pFrame); if (iRet != 0) { int a = 0; a = iRet; } got_picture = avcodec_receive_packet(pCodecCtx, &pkt); SendToRTSP(pInf, pkt.data + 4, pkt.size - 4);//傳送到RTSP流進行傳輸,注意已去掉H264預設的00 00 00 01頭 av_packet_unref(&pkt); delete[] p; } //注意!未做釋放! return 0; }
以上程式碼實現了實時視訊資料的H264編碼格式,需要修改解析度、幀率和碼流,H264資料中未新增時間戳,某些播放器可能無法播放。新版本的ffmpeg庫與之前的有些不同,需要對應修改。