📄 main.c
字号:
muxer->last_br_time = now; muxer->pck_sent=0; } } return ret;}typedef struct{ GF_ISOFile *mp4; u32 track, sample_number, sample_count; GF_ISOSample *sample;} GF_ESIMP4;static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param){ GF_ESIMP4 *priv = (GF_ESIMP4 *)ifce->input_udta; if (!priv) return GF_BAD_PARAM; switch (act_type) { case GF_ESI_INPUT_DATA_FLUSH: return GF_OK; case GF_ESI_INPUT_DATA_PULL: { GF_ESIPacket *pck = (GF_ESIPacket *)param; if (!priv->sample) { priv->sample = gf_isom_get_sample(priv->mp4, priv->track, priv->sample_number+1, NULL); } if (!priv->sample) return GF_IO_ERR; pck->dts = priv->sample->DTS; pck->cts = priv->sample->DTS + priv->sample->CTS_Offset; pck->data_len = priv->sample->dataLength; pck->data = priv->sample->data; pck->flags = GF_ESI_DATA_AU_START | GF_ESI_DATA_AU_END; if (priv->sample->IsRAP) pck->flags |= GF_ESI_DATA_AU_RAP; } return GF_OK; case GF_ESI_INPUT_DATA_RELEASE: if (priv->sample) { gf_isom_sample_del(&priv->sample); priv->sample_number++; if (priv->sample_number==priv->sample_count) ifce->caps |= GF_ESI_STREAM_IS_OVER; } return GF_OK; case GF_ESI_INPUT_DESTROY: free(priv); ifce->input_udta = NULL; return GF_OK; default: return GF_BAD_PARAM; }}static void fill_isom_es_ifce(GF_ESInterface *ifce, GF_ISOFile *mp4, u32 track_num){ GF_ESIMP4 *priv; char _lan[4]; GF_DecoderConfig *dcd; u64 avg_rate; GF_SAFEALLOC(priv, GF_ESIMP4); priv->mp4 = mp4; priv->track = track_num; priv->sample_count = gf_isom_get_sample_count(mp4, track_num); memset(ifce, 0, sizeof(GF_ESInterface)); ifce->caps = GF_ESI_AU_PULL_CAP; ifce->stream_id = gf_isom_get_track_id(mp4, track_num); dcd = gf_isom_get_decoder_config(mp4, track_num, 1); ifce->stream_type = dcd->streamType; ifce->object_type_indication = dcd->objectTypeIndication; gf_odf_desc_del((GF_Descriptor *)dcd); gf_isom_get_media_language(mp4, track_num, _lan); ifce->lang = GF_4CC(_lan[0],_lan[1],_lan[2],' '); ifce->timescale = gf_isom_get_media_timescale(mp4, track_num); ifce->duration = gf_isom_get_media_timescale(mp4, track_num); avg_rate = gf_isom_get_media_data_size(mp4, track_num); avg_rate *= ifce->timescale * 8; avg_rate /= gf_isom_get_media_duration(mp4, track_num); if (gf_isom_has_time_offset(mp4, track_num)) ifce->caps |= GF_ESI_SIGNAL_DTS; ifce->bit_rate = (u32) avg_rate; ifce->duration = (Double) (s64) gf_isom_get_media_duration(mp4, track_num); ifce->duration /= ifce->timescale; ifce->input_ctrl = mp4_input_ctrl; ifce->input_udta = priv;}typedef struct{ /*RTP channel*/ GF_RTPChannel *rtp_ch; /*depacketizer*/ GF_RTPDepacketizer *depacketizer; GF_ESIPacket pck; GF_ESInterface *ifce;} GF_ESIRTP;static GF_Err rtp_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param){ u32 size, PayloadStart; GF_Err e; GF_RTPHeader hdr; char buffer[8000]; GF_ESIRTP *rtp = (GF_ESIRTP*)ifce->input_udta; if (!ifce->input_udta) return GF_BAD_PARAM; switch (act_type) { case GF_ESI_INPUT_DATA_FLUSH: /*flush rtp channel*/ while (1) { size = gf_rtp_read_rtp(rtp->rtp_ch, buffer, 8000); if (!size) break; e = gf_rtp_decode_rtp(rtp->rtp_ch, buffer, size, &hdr, &PayloadStart); if (e) return e; gf_rtp_depacketizer_process(rtp->depacketizer, &hdr, buffer + PayloadStart, size - PayloadStart); } /*flush rtcp channel*/ while (1) { size = gf_rtp_read_rtcp(rtp->rtp_ch, buffer, 8000); if (!size) break; e = gf_rtp_decode_rtcp(rtp->rtp_ch, buffer, size); if (e == GF_EOS) ifce->caps |= GF_ESI_STREAM_IS_OVER; } return GF_OK; case GF_ESI_INPUT_DESTROY: gf_rtp_depacketizer_del(rtp->depacketizer); gf_rtp_del(rtp->rtp_ch); free(rtp); ifce->input_udta = NULL; return GF_OK; } return GF_OK;}static void rtp_sl_packet_cbk(void *udta, char *payload, u32 size, GF_SLHeader *hdr, GF_Err e){ GF_ESIRTP *rtp = (GF_ESIRTP*)udta; rtp->pck.data = payload; rtp->pck.data_len = size; rtp->pck.dts = hdr->decodingTimeStamp; rtp->pck.cts = hdr->compositionTimeStamp; rtp->pck.flags = 0; if (hdr->compositionTimeStampFlag) rtp->pck.flags |= GF_ESI_DATA_HAS_CTS; if (hdr->decodingTimeStampFlag) rtp->pck.flags |= GF_ESI_DATA_HAS_DTS; if (hdr->randomAccessPointFlag) rtp->pck.flags |= GF_ESI_DATA_AU_RAP; if (hdr->accessUnitStartFlag) rtp->pck.flags |= GF_ESI_DATA_AU_START; if (hdr->accessUnitEndFlag) rtp->pck.flags |= GF_ESI_DATA_AU_END; rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck);}void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInfo *sdp){ u32 i; GF_Err e; GF_X_Attribute*att; GF_ESIRTP *rtp; GF_RTPMap*map; GF_SDPConnection *conn; GF_RTSPTransport trans; /*check connection*/ conn = sdp->c_connection; if (!conn) conn = (GF_SDPConnection*)gf_list_get(media->Connections, 0); /*check payload type*/ map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0); GF_SAFEALLOC(rtp, GF_ESIRTP); memset(ifce, 0, sizeof(GF_ESInterface)); rtp->rtp_ch = gf_rtp_new(); i=0; while ((att = (GF_X_Attribute*)gf_list_enum(media->Attributes, &i))) { if (!stricmp(att->Name, "mpeg4-esid") && att->Value) ifce->stream_id = atoi(att->Value); } memset(&trans, 0, sizeof(GF_RTSPTransport)); trans.Profile = media->Profile; trans.source = conn ? conn->host : sdp->o_address; trans.IsUnicast = gf_sk_is_multicast_address(trans.source) ? 0 : 1; if (!trans.IsUnicast) { trans.port_first = media->PortNumber; trans.port_last = media->PortNumber + 1; trans.TTL = conn ? conn->TTL : 0; } else { trans.client_port_first = media->PortNumber; trans.client_port_last = media->PortNumber + 1; } if (gf_rtp_setup_transport(rtp->rtp_ch, &trans, NULL) != GF_OK) { gf_rtp_del(rtp->rtp_ch); fprintf(stdout, "Cannot initialize RTP transport\n"); return; } /*setup depacketizer*/ rtp->depacketizer = gf_rtp_depacketizer_new(media, rtp_sl_packet_cbk, rtp); if (!rtp->depacketizer) { gf_rtp_del(rtp->rtp_ch); fprintf(stdout, "Cannot create RTP depacketizer\n"); return; } /*setup channel*/ gf_rtp_setup_payload(rtp->rtp_ch, map); ifce->input_udta = rtp; ifce->input_ctrl = rtp_input_ctrl; rtp->ifce = ifce; ifce->object_type_indication = rtp->depacketizer->sl_map.ObjectTypeIndication; ifce->stream_type = rtp->depacketizer->sl_map.StreamType; ifce->timescale = gf_rtp_get_clockrate(rtp->rtp_ch); /*DTS signaling is only supported for MPEG-4 visual*/ if (rtp->depacketizer->sl_map.DTSDeltaLength) ifce->caps |= GF_ESI_SIGNAL_DTS; gf_rtp_depacketizer_reset(rtp->depacketizer, 1); e = gf_rtp_initialize(rtp->rtp_ch, 0x100000ul, 0, 0, 10, 200, NULL); if (e!=GF_OK) { gf_rtp_del(rtp->rtp_ch); fprintf(stdout, "Cannot initialize RTP channel: %s\n", gf_error_to_string(e)); return; } fprintf(stdout, "RTP interface initialized\n");}#define MAX_MUX_SRC_PROG 100typedef struct{ GF_ISOFile *mp4; u32 nb_streams, pcr_idx; GF_ESInterface streams[40];} M2TSProgram;Bool open_program(M2TSProgram *prog, const char *src){ GF_SDPInfo *sdp; u32 i; GF_Err e; memset(prog, 0, sizeof(M2TSProgram)); /* Open ISO file */ if (gf_isom_probe_file(src)) { prog->mp4 = gf_isom_open(src, GF_ISOM_OPEN_READ, 0); prog->nb_streams = gf_isom_get_track_count(prog->mp4); for (i=0; i<prog->nb_streams; i++) { fill_isom_es_ifce(&prog->streams[i], prog->mp4, i+1); /*get first visual stream as PCR*/ if (!prog->pcr_idx && (gf_isom_get_media_type(prog->mp4, i+1) == GF_ISOM_MEDIA_VISUAL) && (gf_isom_get_sample_count(prog->mp4, i+1)>1) ) { prog->pcr_idx = i+1; } } if (prog->pcr_idx) prog->pcr_idx-=1; return 1; } /*open SDP file*/ if (strstr(src, ".sdp")) { char *sdp_buf; u32 sdp_size; FILE *_sdp = fopen(src, "rt"); if (!_sdp) { fprintf(stderr, "Error opening %s - no such file\n", src); return 0; } fseek(_sdp, 0, SEEK_END); sdp_size = ftell(_sdp); fseek(_sdp, 0, SEEK_SET); sdp_buf = (char*)malloc(sizeof(char)*sdp_size); memset(sdp_buf, 0, sizeof(char)*sdp_size); fread(sdp_buf, sdp_size, 1, _sdp); fclose(_sdp); sdp = gf_sdp_info_new(); e = gf_sdp_info_parse(sdp, sdp_buf, sdp_size); free(sdp_buf); if (e) { fprintf(stderr, "Error opening %s : %s\n", src, gf_error_to_string(e)); gf_sdp_info_del(sdp); return 0; } prog->nb_streams = gf_list_count(sdp->media_desc); for (i=0; i<prog->nb_streams; i++) { GF_SDPMedia *media = gf_list_get(sdp->media_desc, i); fill_rtp_es_ifce(&prog->streams[i], media, sdp); if (!prog->pcr_idx && (prog->streams[i].stream_type == GF_STREAM_VISUAL)) { prog->pcr_idx = i+1; } } if (prog->pcr_idx) prog->pcr_idx-=1; gf_sdp_info_del(sdp); return 2; } else { fprintf(stderr, "Error opening %s - not a supported input media, skipping.\n", src); return 0; }}int main(int argc, char **argv){ const char *ts_pck; GF_Err e; u32 res; Bool real_time=0; M2TS_Mux *muxer; u32 i, j, mux_rate, nb_progs, cur_pid; char *ts_out = NULL; FILE *ts_file; GF_Socket *ts_udp; GF_RTPChannel *ts_rtp; GF_RTSPTransport tr; GF_RTPHeader hdr; u16 port = 1234; u32 output_type; M2TSProgram progs[MAX_MUX_SRC_PROG]; output_type = 0; ts_file = NULL; ts_udp = NULL; ts_rtp = NULL; ts_out = NULL; nb_progs = 0; mux_rate = 0; for (i=1; i<argc; i++) { char *arg = argv[i]; if (arg[0]=='-') { if (!strnicmp(arg, "-rate=", 6)) mux_rate = 1024*atoi(arg+6); else if (!strnicmp(arg, "-prog=", 6)) { memset(&progs[nb_progs], 0, sizeof(M2TSProgram)); res = open_program(&progs[nb_progs], arg+6); if (res) { nb_progs++; if (res==2) real_time=1; } } } /*output*/ else { if (!strnicmp(arg, "rtp://", 6) || !strnicmp(arg, "udp://", 6)) { char *sep = strchr(arg+6, ':'); output_type = (arg[0]=='r') ? 1 : 2; real_time=1; if (sep) { port = atoi(sep+1); sep[0]=0; ts_out = strdup(arg); sep[0]=':'; } else { ts_out = strdup(arg+6); } } else if (!strnicmp(arg, "udp://", 6)) { output_type = 1; ts_out = arg; real_time=1; } else { output_type = 0; ts_out = strdup(arg); } } } if (!nb_progs || !ts_out) { usage(); return 0; } gf_log_set_level(GF_LOG_DEBUG); gf_log_set_tools(GF_LOG_RTP);// gf_log_set_tools(GF_LOG_CONTAINER); gf_sys_init(); GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("What a FGucking test!!\n")); muxer = m2ts_mux_new(mux_rate, real_time); /* Open mpeg2ts file*/ switch(output_type) { case 0: ts_file = fopen(ts_out, "wb"); if (!ts_file ) { fprintf(stderr, "Error opening %s\n", ts_out); goto exit; } break; case 1: ts_udp = gf_sk_new(GF_SOCK_TYPE_UDP); if (gf_sk_is_multicast_address((char *)ts_out)) { e = gf_sk_setup_multicast(ts_udp, (char *)ts_out, port, 0, 0, NULL); } else { e = gf_sk_bind(ts_udp, port, (char *)ts_out, port, GF_SOCK_REUSE_PORT); } if (e) { fprintf(stdout, "Error inhitializing UDP socket: %s\n", gf_error_to_string(e)); goto exit; } break; case 2: ts_rtp = gf_rtp_new(); gf_rtp_set_ports(ts_rtp, port); tr.IsUnicast = gf_sk_is_multicast_address((char *)ts_out) ? 0 : 1; tr.Profile="RTP/AVP"; tr.destination = (char *)ts_out; tr.source = "0.0.0.0"; tr.IsRecord = 0; tr.Append = 0; tr.SSRC = rand(); tr.port_first = port; tr.port_last = port+1; if (tr.IsUnicast) { tr.client_port_first = port; tr.client_port_last = port+1; } else { tr.source = (char *)ts_out; } res = gf_rtp_setup_transport(ts_rtp, &tr, (char *)ts_out); if (res !=0) { fprintf(stdout, "Cannot setup RTP transport info\n"); goto exit; } res = gf_rtp_initialize(ts_rtp, 0, 1, 1500, 0, 0, NULL); if (res !=0) { fprintf(stdout, "Cannot initialize RTP sockets\n"); goto exit; } memset(&hdr, 0, sizeof(GF_RTPHeader)); hdr.Version = 2; hdr.PayloadType = 33; /*MP2T*/ hdr.SSRC = tr.SSRC; hdr.Marker = 0; break; } cur_pid = 100; for (i=0; i<nb_progs; i++) { M2TS_Mux_Program *program = m2ts_mux_program_add(muxer, i+1, cur_pid); for (j=0; j<progs[i].nb_streams; j++) { m2ts_program_stream_add(program, &progs[i].streams[j], cur_pid+j+1, (progs[i].pcr_idx==j) ? 1 : 0); } cur_pid += progs[i].nb_streams; while (cur_pid % 10) cur_pid ++; } m2ts_mux_update_config(muxer, 1); while (1) { u32 ts; u32 status; /*flush all packets*/ switch (output_type) { case 0: while ((ts_pck = m2ts_mux_process(muxer, &status)) != NULL) { fwrite(ts_pck, 1, 188, ts_file); if (status>=GF_M2TS_STATE_PADDING) break; } break; case 1: while ((ts_pck = m2ts_mux_process(muxer, &status)) != NULL) { e = gf_sk_send(ts_udp, (char*)ts_pck, 188); if (e) fprintf(stdout, "Error %s sending UDP packet\n", gf_error_to_string(e)); if (status>=GF_M2TS_STATE_PADDING) break; } break; case 2: while ((ts_pck = m2ts_mux_process(muxer, &status)) != NULL) { hdr.SequenceNumber++; /*muxer clock at 90k*/ ts = muxer->time.sec*90000 + muxer->time.nanosec*9/100000; /*FIXME - better discontinuity check*/ hdr.Marker = (ts < hdr.TimeStamp) ? 1 : 0; hdr.TimeStamp = ts; e = gf_rtp_send_packet(ts_rtp, &hdr, 0, 0, (char*)ts_pck, 188); if (e) fprintf(stdout, "Error %s sending RTP packet\n", gf_error_to_string(e)); if (status>=GF_M2TS_STATE_PADDING) break; } break; } if (real_time) { /*abort*/ if (gf_prompt_has_input()) { char c = gf_prompt_get_char(); if (c == 'q') break; } fprintf(stdout, "M2TS: time %d - TS time %d - avg bitrate %d\r", gf_m2ts_get_sys_clock(muxer), gf_m2ts_get_ts_clock(muxer), muxer->avg_br); } else { if (status==GF_M2TS_STATE_EOS) break; } }exit: if (ts_file) fclose(ts_file); if (ts_udp) gf_sk_del(ts_udp); if (ts_rtp) gf_rtp_del(ts_rtp); if (ts_out) free(ts_out); m2ts_mux_del(muxer); for (i=0; i<nb_progs; i++) { for (j=0; j<progs[i].nb_streams; j++) { progs[i].streams[j].input_ctrl(&progs[i].streams[j], GF_ESI_INPUT_DESTROY, NULL); } if (progs[i].mp4) gf_isom_close(progs[i].mp4); } gf_sys_close(); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -