ortp學習筆記

來源:互聯網
上載者:User

ortp版本:ortp-0.18.0.tar.gz  

作業系統:window 7 32bit
1.windows下編譯ortp.lib直接開啟ortp-0.18.0\build\win32native的工程檔案即可,VS2008下無需任何修改,即可編譯出動態連結程式庫 ortp.lib以及ortp.dll。
2.使用ortp提供的測試程式:ortp-0.18.0\src\tests下的win_receive以及win_sender目錄下程式在windows7下使用win_receiver時會提示下如下錯誤,這個在錯誤在windows XP下是不存在的 QOSAddSocketToFlow failed to add a flow with error 87具體問題暫時還沒有深究,這個應該是一個系統相容性問題,需要系統支援qwave.lib。在尋找了錯誤出處,對比了前幾個ortp的版本後,對ortp0.18的原始碼進行了修改
rtp_session_inet.c
/* set socket options (but don't change chosen states) */
/*
          rtp_session_set_dscp( session, -1 );
          rtp_session_set_multicast_ttl( session, -1 );
          rtp_session_set_multicast_loopback( session, -1 );
*/

3. 發送H.264視訊框架ortp提供的win_receive以及win_sender一次只發送160位元組的資料。但我們在發送一幀H.264視訊框架,每次需要發送2000-3000位元組的資料,關於ortp發送H.264視訊框架,可以參考:ortp編程範例程式碼談談RTP傳輸中的負載類型和時間戳記除了上面兩篇文章提到需要注意的負載類型和時間戳記之外,在ortp中win_receive中還需要顯示調用:rtp_session_set_recv_buf_size(rtp_session_mgr .rtp_session , recv_bufsize);這裡的recv_bufsize必須要比win_sender中sended_bytes = rtp_session_send_with_ts (rtp_session_mgr .rtp_session ,                          ( uint8_t *) send_buffer,                           wrapLen,                          rtp_session_mgr.cur_timestamp );的wrapLen要大,否則在receive端會出現如下錯誤: ortp-warning-Error receiving RTP packet: Error code : 10040, err num [10040],error [-1]
4. 一個結合H.264編碼,rtp發送,接收,儲存mp4檔案的小程式

:ortp測試程式(修改版)編譯環境:vs2008壓縮檔中包括了ffmpeg以及ortp的動態連結程式庫,但你還需要在工程檔案中修改它們的路徑才能正確連結這兩個庫.因為這個小程式是一個項目的一部分,原始碼中還有些冗餘代碼,並沒有來的及刪掉,大家在看的時候需要注意下
receiver
#include <string.h>#include "ortp/ortp.h"extern "C"{#include <libavformat/avformat.h>#include <libswscale/swscale.h>};bool m_bExit = FALSE;struct RtpSessionMgr{RtpSession *rtp_session;int timestamp;};RtpSessionMgr rtp_session_mgr;const int timestamp_inc = 3600; // 90000/25const char recv_ip[] = "127.0.0.1";const int recv_port = 8008;const int recv_bufsize = 10240;unsigned char *recv_buf;/** 幀包頭的標識長度 */ #define CMD_HEADER_LEN 10/** 幀包頭的定義 */static uint8_t CMD_HEADER_STR[CMD_HEADER_LEN] = { 0xAA,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xFF };/** 幀的包頭資訊 */typedef struct _sFrameHeader{/** 命令名稱標識 */ unsigned char cmdHeader[CMD_HEADER_LEN];/** 採集的通道號 0~7*/unsigned char chId;/** 資料類型,音頻 或者 視頻*/unsigned char dataType; /** 緩衝區的資料長度 */ uint32_t len;/** 時間戳記 */uint32_t timestamp;}FrameHeader;///////ffmpeg///////////////////////////////////////////////////////////////////AVOutputFormat *fmt;AVFormatContext *oc;AVStream *video_st;AVCodecContext *codecContext;const int image_width = 704;const int image_height = 576;const int frame_rate = 25;static int frame_count;BOOL ctrlHandlerFunction(DWORD fdwCtrlType) { switch (fdwCtrlType) { // Handle the CTRL+C signal. // CTRL+CLOSE: confirm that the user wants to exit. case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: m_bExit = TRUE;return TRUE; default: return FALSE; } } void rtpInit(){int ret;WSADATA wsaData;/** 初始化winsocket */ if ( WSAStartup(MAKEWORD(2,2), &wsaData) != 0){fprintf(stderr, "WAStartup failed!\n");return ;}ortp_init();ortp_scheduler_init();rtp_session_mgr.rtp_session = rtp_session_new(RTP_SESSION_RECVONLY);rtp_session_set_scheduling_mode(rtp_session_mgr.rtp_session, 1);rtp_session_set_blocking_mode(rtp_session_mgr.rtp_session, 1);rtp_session_set_local_addr(rtp_session_mgr.rtp_session, recv_ip, recv_port);rtp_session_enable_adaptive_jitter_compensation(rtp_session_mgr.rtp_session, TRUE);rtp_session_set_jitter_compensation(rtp_session_mgr.rtp_session, 40);rtp_session_set_payload_type(rtp_session_mgr.rtp_session, 34);rtp_session_set_recv_buf_size(rtp_session_mgr.rtp_session, recv_bufsize);rtp_session_mgr.timestamp = timestamp_inc;}int rtp2disk(){int err;int havemore = 1;while (havemore){err = rtp_session_recv_with_ts(rtp_session_mgr.rtp_session, (uint8_t *)recv_buf, recv_bufsize, rtp_session_mgr.timestamp, &havemore);if (havemore) printf("==> Warning: havemore=1!\n");if (err > 0){FrameHeader *frameHeader;printf("receive data is %d\n", err);frameHeader = (FrameHeader *)recv_buf;printf("frame_len = %d\n", frameHeader->len);AVPacket pkt;av_init_packet(&pkt);pkt.stream_index= video_st->index;pkt.data= recv_buf + sizeof(FrameHeader);pkt.size = frameHeader->len; // not the video_outbuf_size, note!// write the compressed frame in the media fileerr = av_write_frame(oc, &pkt);if (err != 0){printf("av_write_frame failed\n");}}}return 0;}AVCodecContext* createCodecContext(AVFormatContext *oc){AVCodecContext *video_cc = avcodec_alloc_context();video_cc =  avcodec_alloc_context();if (!video_cc){fprintf(stderr, "alloc avcodec context failed\n");exit(1);}video_cc->codec_id = (CodecID)CODEC_ID_H264;video_cc->codec_type = AVMEDIA_TYPE_VIDEO;video_cc->me_range = 16;  video_cc->max_qdiff = 4;  video_cc->qmin = 10;  video_cc->qmax = 51;  video_cc->qcompress = 0.6f;  /* put sample parameters */video_cc->bit_rate = 400000;/* resolution must be a multiple of two */video_cc->width = image_width;video_cc->height = image_height;/* time base: this is the fundamental unit of time (in seconds) in termsof which frame timestamps are represented. for fixed-fps content,timebase should be 1/framerate and timestamp increments should beidentically 1. */video_cc->time_base.den = frame_rate;video_cc->time_base.num = 1;video_cc->gop_size = 12; /* emit one intra frame every twelve frames at most */video_cc->pix_fmt = PIX_FMT_YUV420P;// some formats want stream headers to be separateif(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))video_cc->flags |= CODEC_FLAG_GLOBAL_HEADER;return video_cc;}void openVideo(AVFormatContext *oc){AVCodec *codec;/* find the video encoder */codec = avcodec_find_encoder(codecContext->codec_id);if (!codec) {fprintf(stderr, "codec not found\n");exit(1);}/* open the codec */if (avcodec_open(codecContext, codec) < 0) {fprintf(stderr, "could not open video codec\n");exit(1);}}void ffmpegEncodeInit(){// initialize libavcodec, and register all codecs and formatsav_register_all();char filename[] = "test.mp4";fmt = av_guess_format(NULL, filename, NULL);oc = avformat_alloc_context();oc->oformat = fmt;fmt->video_codec = (CodecID) CODEC_ID_H264;_snprintf(oc->filename, sizeof(oc->filename), "%s", filename);// add the video streams using the default format codecs and initialize the codecsvideo_st = NULL;if (fmt->video_codec != CODEC_ID_NONE) {video_st = av_new_stream(oc, 0);if (!video_st) {fprintf(stderr, "Could not alloc stream\n");exit(1);}}// alloc codecContextcodecContext = createCodecContext(oc);video_st->codec = codecContext;// set the output parameters (must be done even if no parameters).if (av_set_parameters(oc, NULL) < 0) {fprintf(stderr, "Invalid output format parameters\n");exit(1);}dump_format(oc, 0, filename, 1);/* now that all the parameters are set, we can open the audio andvideo codecs and allocate the necessary encode buffers */if (codecContext)openVideo(oc);// open the output file, if neededif (!(fmt->flags & AVFMT_NOFILE)) {if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {fprintf(stderr, "Could not open '%s'\n", filename);exit(1);}}// write the stream header, if anyav_write_header(oc);}void ffmpegEncodeClose(){int i;/* close each codec */if (video_st)avcodec_close(video_st->codec);// write the trailer, if anyav_write_trailer(oc);/* free the streams */for(i = 0; i < oc->nb_streams; i++) {av_freep(&oc->streams[i]->codec);av_freep(&oc->streams[i]);}if (!(fmt->flags & AVFMT_NOFILE)) {/* close the output file */url_fclose(oc->pb);}/* free the stream */av_free(oc);}int main(){recv_buf = (uint8_t *)malloc(recv_bufsize);rtpInit();ffmpegEncodeInit();// =============== INSTALL THE CONTROL HANDLER ===============if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrlHandlerFunction, TRUE) == 0){printf("==> Cannot handle the CTRL-C...\n");}printf("==> RTP Receiver started\n");while (m_bExit == FALSE){rtp2disk();rtp_session_mgr.timestamp += timestamp_inc;}printf("==> Exiting\n");free(recv_buf);ffmpegEncodeClose();rtp_session_destroy(rtp_session_mgr.rtp_session);ortp_exit();}

sender

#include <ortp/ortp.h>#include <string.h>extern "C"{#include <libavformat/avformat.h>#include <libswscale/swscale.h>};struct RtpSessionMgr{RtpSession *rtp_session;uint32_t timestamp_inc;uint32_t cur_timestamp;};RtpSessionMgr rtp_session_mgr;const char g_ip[] = "127.0.0.1";const int g_port = 8008;const uint32_t timestamp_inc = 3600; // 90000 / 25const int image_width = 704;const int image_height = 576;const int frame_rate = 25;static int frame_count, wrap_size;AVCodecContext *video_cc;AVFrame *picture;/** 幀包頭的標識長度 */ #define CMD_HEADER_LEN 10/** 幀包頭的定義 */static uint8_t CMD_HEADER_STR[CMD_HEADER_LEN] = { 0xAA,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xFF };/** 幀的包頭資訊 */typedef struct _sFrameHeader{/** 命令名稱標識 */ unsigned char cmdHeader[CMD_HEADER_LEN];/** 採集的通道號 0~7*/unsigned char chId;/** 資料類型,音頻 或者 視頻*/unsigned char dataType; /** 緩衝區的資料長度 */ uint32_t len;/** 時間戳記 */uint32_t timestamp;}FrameHeader;// set frame header FrameHeader frameHeader;void rtpInit(){char *m_SSRC;ortp_init();ortp_scheduler_init();printf("Scheduler initialized\n");rtp_session_mgr.rtp_session = rtp_session_new(RTP_SESSION_SENDONLY);rtp_session_set_scheduling_mode(rtp_session_mgr.rtp_session, 1);rtp_session_set_blocking_mode(rtp_session_mgr.rtp_session, 1);rtp_session_set_remote_addr(rtp_session_mgr.rtp_session, g_ip, g_port);rtp_session_set_send_payload_type(rtp_session_mgr.rtp_session, 34); // 34 is for H.263 video framem_SSRC= getenv("SSRC");if (m_SSRC != NULL) {rtp_session_set_ssrc(rtp_session_mgr.rtp_session, atoi(m_SSRC));}rtp_session_mgr.cur_timestamp = 0;rtp_session_mgr.timestamp_inc = timestamp_inc;printf("rtp init success!\n");}int rtpSend(unsigned char *send_buffer, int frame_len){FrameHeader *fHeader = (FrameHeader *)send_buffer;fHeader->chId      = 0;fHeader->dataType  = 0; // SESSION_TYPE_VIDEOfHeader->len       = frame_len;fHeader->timestamp = 0;printf("frame header len = %d\n", fHeader->len);int wrapLen;wrapLen = frame_len + sizeof(FrameHeader);int sended_bytes;sended_bytes = rtp_session_send_with_ts(rtp_session_mgr.rtp_session, (uint8_t *)send_buffer, wrapLen,rtp_session_mgr.cur_timestamp);rtp_session_mgr.cur_timestamp += rtp_session_mgr.timestamp_inc;return sended_bytes;}void createCodecContext(){video_cc =  avcodec_alloc_context();if (!video_cc){fprintf(stderr, "alloc avcodec context failed\n");exit(1);}video_cc->codec_id = (CodecID)CODEC_ID_H264;video_cc->codec_type = AVMEDIA_TYPE_VIDEO;video_cc->me_range = 16;  video_cc->max_qdiff = 4;  video_cc->qmin = 10;  video_cc->qmax = 51;  video_cc->qcompress = 0.6f;  /* put sample parameters */video_cc->bit_rate = 400000;/* resolution must be a multiple of two */video_cc->width = image_width;video_cc->height = image_height;/* time base: this is the fundamental unit of time (in seconds) in termsof which frame timestamps are represented. for fixed-fps content,timebase should be 1/framerate and timestamp increments should beidentically 1. */video_cc->time_base.den = frame_rate;video_cc->time_base.num = 1;video_cc->gop_size = 12; /* emit one intra frame every twelve frames at most */video_cc->pix_fmt = PIX_FMT_YUV420P;}AVFrame *allocPicture(int pix_fmt, int width, int height){AVFrame *picture;uint8_t *picture_buf;int size;picture = avcodec_alloc_frame();if (!picture)return NULL;size = avpicture_get_size((PixelFormat)pix_fmt, width, height);picture_buf = (uint8_t *)av_malloc(size);if (!picture_buf) {av_free(picture);return NULL;}avpicture_fill((AVPicture *)picture, picture_buf, (PixelFormat)pix_fmt, width, height);return picture;}void openVideo(){AVCodec *video_codec;/* find the video encoder */video_codec = avcodec_find_encoder(video_cc->codec_id);if (!video_codec) {fprintf(stderr, "codec not found\n");exit(1);}/* open the codec */if (avcodec_open(video_cc, video_codec) < 0) {fprintf(stderr, "could not open video codec\n");exit(1);}/* allocate the encoded raw picture */picture = allocPicture(video_cc->pix_fmt, video_cc->width, video_cc->height);if (!picture) {fprintf(stderr, "Could not allocate picture\n");exit(1);}}/* prepare a dummy image */void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height){int x, y, i;i = frame_index;/* Y */for(y=0;y<height;y++) {for(x=0;x<width;x++) {pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;}}/* Cb and Cr */for(y=0;y<height/2;y++) {for(x=0;x<width/2;x++) {pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;}}}void ffmpegInit(){// initialize libavcodec, and register all codecs and formatsav_register_all();// create a codec contextcreateCodecContext();// open H.264 codecopenVideo();}void getEncodedFrame(unsigned char *buffer, int& len){int out_size;fill_yuv_image(picture, frame_count, video_cc->width, video_cc->height);// encode the frameout_size = avcodec_encode_video(video_cc, buffer, wrap_size-sizeof(FrameHeader), picture);len = out_size;frame_count++;}int main(){unsigned char *send_outbuf;unsigned char *video_part;frame_count = 0;wrap_size = 20000;send_outbuf = (unsigned char *)malloc(wrap_size);// copy cmdHeader to frameInfomemcpy(frameHeader.cmdHeader,CMD_HEADER_STR,CMD_HEADER_LEN);memcpy(send_outbuf, &frameHeader, sizeof(FrameHeader));video_part = send_outbuf + sizeof(FrameHeader);ffmpegInit();rtpInit();while (1){int frame_len;// get encode framegetEncodedFrame(video_part, frame_len);printf("encodecFrame length is : %d\n", frame_len);if (frame_len > 0){rtpSend(send_outbuf, frame_len);}}rtp_session_destroy(rtp_session_mgr.rtp_session);free(send_outbuf);// Give us some timeSleep(250);ortp_exit();}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.