📄 main.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Cyril Concolato / Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / mp4 simple streamer application * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/isomedia.h>#include <gpac/ietf.h>#include <gpac/config.h>#include <gpac/base_coding.h>GP_RTPPacketizer *gf_rtp_packetizer_create_and_init_from_file(GF_ISOFile *file, u32 TrackNum, void *cbk_obj, void (*OnNewPacket)(void *cbk, GF_RTPHeader *header), void (*OnPacketDone)(void *cbk, GF_RTPHeader *header), void (*OnDataReference)(void *cbk, u32 payload_size, u32 offset_from_orig), void (*OnData)(void *cbk, char *data, u32 data_size, Bool is_head), u32 Path_MTU, u32 max_ptime, u32 default_rtp_rate, u32 flags, u8 PayloadID, Bool copy_media, u32 InterleaveGroupID, u8 InterleaveGroupPriority);void gf_hinter_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, char *sdpLine, GF_ISOFile *file, u32 track);//------------------------------------------------------------// Define//------------------------------------------------------------#define PATHFILE "."#define RTP_HEADER_SIZE 12 // in bytes (octets)#define BASE_PAYT 96//------------------------------------------------------------// Typedef//------------------------------------------------------------enum{ LOG_NONE = 0, LOG_BURST, LOG_AU, LOG_PACKET,};typedef struct { u32 log_level; u32 path_mtu; struct __tag_rtp_session *session; u8 payt; Bool burst_mode; /*burst mode configuration*/ u32 burstDuration; u32 burstBitRate; u32 burstSize; u32 offDuration; u32 averageBitRate; u32 cycleDuration; u32 nbBurstSent;} Streamer;typedef struct __tag_rtp_pck { struct __tag_rtp_pck *next; GF_RTPHeader header; char *payload; u32 payload_len;} RTP_Packet;typedef struct __tag_rtp_stream{ struct __tag_rtp_stream *next; u32 current_au; u32 nb_aus; u32 port; GF_RTPChannel *channel; GP_RTPPacketizer *packetizer; GF_ISOSample *au; // the AU u32 track; u32 sample_duration; u32 sample_desc_index; /*normalized DTS in micro-sec*/ u64 microsec_dts; /* The previous packet which could not be sent in previous burst*/ RTP_Packet *pck_queue; /* The current packet being formed */ RTP_Packet packet; u32 ts_offset, microsec_ts_offset; u32 next_ts; Double ts_scale, microsec_ts_scale; Bool process_burst; struct __tag_rtp_session *session;} RTP_Stream;typedef struct __tag_rtp_session{ struct __tag_rtp_session *next; u32 id; u32 minBurstSize; // max size to fill the burst with the media bitRate u32 looping; // 1: play the media in a loop, 0 play once char *filename; GF_ISOFile *mp4File; u32 nbBurstSent; // pour cette session u32 timelineOrigin; // time when the first burts was sent. this time <=> (CTS=0) u32 nextBurstTime; u32 dataLengthInBurst; // total bytes filled in current burst s32 drift; Bool force_mpeg4_generic; /*list of streams in session*/ RTP_Stream *stream; /*to sync looping sessions with tracks of # length*/ u32 duration; Streamer *streamer;} RTP_Session;static void rtp_flush_channel(RTP_Stream *rtp){ u32 currentPacketSize; RTP_Packet *pck = rtp->pck_queue; while (pck) { RTP_Packet *tmp = pck; gf_rtp_send_packet(rtp->channel, &pck->header, 0, 0, pck->payload, pck->payload_len); currentPacketSize = (pck->payload_len + RTP_HEADER_SIZE); rtp->session->dataLengthInBurst+= currentPacketSize; if (rtp->session->streamer->log_level == LOG_PACKET) fprintf(stdout, " RTP SN %u - TS %u - M %u - Size %u\n", pck->header.SequenceNumber, pck->header.TimeStamp, pck->header.Marker, currentPacketSize); pck = pck->next; free(tmp->payload); free(tmp); } rtp->pck_queue = NULL;}/* * callback functions, called by the RTP packetiser *//* * The RTP packetizer is starting a new RTP packet and is giving the header */static void burst_on_pck_new(void *cbk, GF_RTPHeader *header){ RTP_Stream *rtp = cbk; if (!header) return; memcpy(&rtp->packet.header, header, sizeof(GF_RTPHeader));} /* OnNewPacket *//* * The RTP packetiser is done with the current RTP packet * the header may have changed since the beginning of the packet (OnNewPacket) * */static void burst_on_pck_done(void *cbk, GF_RTPHeader *header) { GF_Err e; s64 burst_time, rtp_ts; RTP_Stream *rtp = cbk; u32 currentPacketSize; // in bits currentPacketSize = (rtp->packet.payload_len + RTP_HEADER_SIZE); burst_time = (s64) rtp->packetizer->sl_config.timestampResolution * (rtp->session->nextBurstTime + rtp->session->streamer->cycleDuration); rtp_ts = (s64) rtp->next_ts*1000; if (rtp->session->dataLengthInBurst + currentPacketSize < rtp->session->streamer->burstSize && (burst_time - rtp_ts > 0) ) { e = gf_rtp_send_packet(rtp->channel, header, 0, 0, rtp->packet.payload, rtp->packet.payload_len); if (e) fprintf(stdout, "Error %s sending RTP packet\n", gf_error_to_string(e)); rtp->session->dataLengthInBurst += currentPacketSize; free(rtp->packet.payload); rtp->packet.payload = NULL; rtp->packet.payload_len = 0; if (rtp->session->streamer->log_level == LOG_PACKET) fprintf(stdout, " RTP SN %u - TS %u - M %u - Size %u\n", rtp->packet.header.SequenceNumber, rtp->packet.header.TimeStamp, rtp->packet.header.Marker, currentPacketSize); } else { RTP_Packet *pck; if (rtp->session->dataLengthInBurst + currentPacketSize > rtp->session->streamer->burstSize) { if (rtp->session->streamer->log_level >= LOG_BURST) fprintf(stdout, " Packet (TS %u) delayed due to buffer overflow\n", rtp->next_ts); } else { if (rtp->session->streamer->log_level==LOG_PACKET) fprintf(stdout, " Packet (TS %u) delayed to avoid drift\n", rtp->next_ts); } GF_SAFEALLOC(pck, RTP_Packet); memcpy(&pck->header, header, sizeof(GF_RTPHeader)); pck->payload = rtp->packet.payload; pck->payload_len = rtp->packet.payload_len; rtp->packet.payload = NULL; rtp->packet.payload_len = 0; rtp->process_burst = 0; if (rtp->pck_queue) { RTP_Packet *first = rtp->pck_queue; while (first->next) first = first->next; first->next = pck; } else { rtp->pck_queue = pck; } }} /* OnPacketdone *//* * The RTP packetiser has added data to the current RTP packet */static void burst_on_pck_data(void *cbk, char *data, u32 data_size, Bool is_head) { RTP_Stream *rtp = cbk; if (!data ||!data_size) return; if (!rtp->packet.payload_len) { rtp->packet.payload = malloc(data_size); memcpy(rtp->packet.payload, data, data_size); rtp->packet.payload_len = data_size; } else { rtp->packet.payload = realloc(rtp->packet.payload, rtp->packet.payload_len + data_size); if (!is_head) { memcpy(rtp->packet.payload+rtp->packet.payload_len, data, data_size); } else { memmove(rtp->packet.payload+data_size, rtp->packet.payload, rtp->packet.payload_len); memcpy(rtp->packet.payload, data, data_size); } rtp->packet.payload_len += data_size; } } /* OnData *//* * The RTP packetizer is starting a new RTP packet and is giving the header */static void on_pck_new(void *cbk, GF_RTPHeader *header){ RTP_Stream *rtp = cbk; if (!header) return; memcpy(&rtp->packet.header, header, sizeof(GF_RTPHeader));} /* * The RTP packetiser is done with the current RTP packet * the header may have changed since the beginning of the packet (OnNewPacket) * */static void on_pck_done(void *cbk, GF_RTPHeader *header) { RTP_Stream *rtp = cbk; GF_Err e = gf_rtp_send_packet(rtp->channel, header, 0, 0, rtp->packet.payload, rtp->packet.payload_len); if (e) fprintf(stdout, "Error %s sending RTP packet\n", gf_error_to_string(e)); free(rtp->packet.payload); rtp->packet.payload = NULL; rtp->packet.payload_len = 0; if (rtp->session->streamer->log_level == LOG_PACKET) fprintf(stdout, " RTP SN %u - TS %u - M %u - Size %u\n", rtp->packet.header.SequenceNumber, rtp->packet.header.TimeStamp, rtp->packet.header.Marker, rtp->packet.payload_len + RTP_HEADER_SIZE);}GF_Err rtp_init_packetizer(RTP_Stream *rtp, char *dest_ip){ u32 flags = 0; if (rtp->session->force_mpeg4_generic) flags = GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_FORCE_MPEG4; if (rtp->session->streamer->burst_mode) { rtp->packetizer = gf_rtp_packetizer_create_and_init_from_file(rtp->session->mp4File, rtp->track, rtp, burst_on_pck_new, burst_on_pck_done, NULL, burst_on_pck_data, rtp->session->streamer->path_mtu, 0, 0, flags, rtp->session->streamer->payt, 0, 0, 0); } else { rtp->packetizer = gf_rtp_packetizer_create_and_init_from_file(rtp->session->mp4File, rtp->track, rtp, on_pck_new, on_pck_done, NULL, burst_on_pck_data, rtp->session->streamer->path_mtu, 0, 0, flags, rtp->session->streamer->payt, 0, 0, 0); } rtp->session->streamer->payt++; rtp->ts_scale = rtp->packetizer->sl_config.timestampResolution; rtp->ts_scale /= gf_isom_get_media_timescale(rtp->session->mp4File, rtp->track); rtp->microsec_ts_scale = 1000000; rtp->microsec_ts_scale /= gf_isom_get_media_timescale(rtp->session->mp4File, rtp->track); return GF_OK;}GF_Err rtp_setup_sdp(RTP_Session *session, char *dest_ip){ RTP_Stream *rtp; FILE *sdp_out; char filename[30]; char mediaName[30], payloadName[30]; char sdpLine[20000]; sprintf(filename, "session%d.sdp", session->id); sdp_out = fopen(filename, "wt"); if (!sdp_out) return GF_IO_ERR; sprintf(sdpLine, "v=0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "o=MP4Streamer 3357474383 1148485440000 IN IP%d %s", gf_net_is_ipv6(dest_ip) ? 6 : 4, dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "s=livesession"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "i=This is an MP4 time-sliced Streaming demo"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "u=http://gpac.sourceforge.net"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "e=admin@"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "c=IN IP%d %s", gf_net_is_ipv6(dest_ip) ? 6 : 4, dest_ip); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "t=0 0"); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "a=x-copyright: Streamed with GPAC (C)2000-200X - http://gpac.sourceforge.net\n"); fprintf(sdp_out, "%s\n", sdpLine); rtp = session->stream; while (rtp) { gf_rtp_builder_get_payload_name(rtp->packetizer, payloadName, mediaName); sprintf(sdpLine, "m=%s %d RTP/%s %d", mediaName, rtp->port, rtp->packetizer->slMap.IV_length ? "SAVP" : "AVP", rtp->packetizer->PayloadType); fprintf(sdp_out, "%s\n", sdpLine); sprintf(sdpLine, "a=rtpmap:%d %s/%d", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution); fprintf(sdp_out, "%s\n", sdpLine); if (gf_isom_get_media_type(rtp->session->mp4File, rtp->track) == GF_ISOM_MEDIA_VISUAL) { u32 w, h; w = h = 0; gf_isom_get_visual_info(rtp->session->mp4File, rtp->track, 1, &w, &h); if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H263) { sprintf(sdpLine, "a=cliprect:0,0,%d,%d", h, w); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -