static GF_Err ISOW_Close(GF_StreamingCache *mc, Bool delete_cache) { GF_Err e; ISOMReader *cache = (ISOMReader *)mc->priv; if (!cache->mov || !cache->service) return GF_BAD_PARAM; while (gf_list_count(cache->channels)) { ISOMChannel *ch = (ISOMChannel *)gf_list_get(cache->channels, 0); gf_list_rem(cache->channels, 0); if (ch->cache_sample) { gf_isom_add_sample(cache->mov, ch->track, 1, ch->cache_sample); gf_isom_sample_del(&ch->cache_sample); } gf_free(ch); } if (delete_cache) { gf_isom_delete(cache->mov); e = GF_OK; } else { e = gf_isom_close(cache->mov); } cache->mov = NULL; cache->service = NULL; return e; }
//写入aac数据,只有raw数据 bool EasyMP4Writer::WriteAACFrame(unsigned char*data,int len,long timestamp) { if (m_audiostartimestamp==-1) { m_audiostartimestamp=timestamp; } p_audiosample->IsRAP=1; p_audiosample->dataLength=len; memcpy( p_audiosample->data,data,len); p_audiosample->DTS=timestamp-m_audiostartimestamp; p_audiosample->CTS_Offset=0; GF_Err gferr=gf_isom_add_sample(p_file,m_audiotrackid,i_audiodescidx,p_audiosample); if (gferr==-1) { p_audiosample->DTS=timestamp-m_audiostartimestamp+15; gf_isom_add_sample(p_file,m_audiotrackid,i_audiodescidx,p_audiosample); } return true; }
//写入一帧,前四字节为该帧NAL长度 bool EasyMP4Writer::WriteH264Frame(unsigned char*data,int len,bool keyframe,long timestamp) { if (m_videostartimestamp==-1&&keyframe) { m_videostartimestamp=timestamp; } if (m_videostartimestamp!=-1) { p_videosample->IsRAP=keyframe; p_videosample->dataLength=len; memcpy(p_videosample->data,data,len); p_videosample->DTS=timestamp-m_videostartimestamp; p_videosample->CTS_Offset=0; GF_Err gferr=gf_isom_add_sample(p_file,m_videtrackid,i_videodescidx,p_videosample); if (gferr==-1) { p_videosample->DTS=timestamp-m_videostartimestamp+15; gf_isom_add_sample(p_file,m_videtrackid,i_videodescidx,p_videosample); } } return true; }
//stores the hint sample in the file //set IsRandomAccessPoint if you want to indicate that this is a random access point //in the stream GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRandomAccessPoint) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 dataRefIndex; GF_Err e; GF_BitStream *bs; GF_ISOSample *samp; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; //first of all, we need to adjust the offset for data referenced IN THIS hint sample //and get some PckSize e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1); if (e) return e; //ok, let's write the sample bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); e = gf_isom_hint_sample_write(entry->hint_sample, bs); if (e) { gf_bs_del(bs); return e; } samp = gf_isom_sample_new(); samp->CTS_Offset = 0; samp->IsRAP = IsRandomAccessPoint; samp->DTS = entry->hint_sample->TransmissionTime; //get the sample gf_bs_get_content(bs, &samp->data, &samp->dataLength); gf_bs_del(bs); //finally add the sample e = gf_isom_add_sample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp); gf_isom_sample_del(&samp); //and delete the sample in our entry ... gf_isom_hint_sample_del(entry->hint_sample); entry->hint_sample = NULL; return e; }
static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture ) { mp4_hnd_t *p_mp4 = handle; int64_t dts; int64_t cts; if( check_buffer( p_mp4, p_mp4->p_sample->dataLength + i_size ) ) return -1; memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size ); p_mp4->p_sample->dataLength += i_size; if( !p_mp4->i_numframe ) p_mp4->i_delay_time = p_picture->i_dts * -1; if( p_mp4->b_dts_compress ) { if( p_mp4->i_numframe == 1 ) p_mp4->i_init_delta = (p_picture->i_dts + p_mp4->i_delay_time) * p_mp4->i_time_inc; dts = p_mp4->i_numframe > p_mp4->i_delay_frames ? p_picture->i_dts * p_mp4->i_time_inc : p_mp4->i_numframe * (p_mp4->i_init_delta / p_mp4->i_dts_compress_multiplier); cts = p_picture->i_pts * p_mp4->i_time_inc; } else { dts = (p_picture->i_dts + p_mp4->i_delay_time) * p_mp4->i_time_inc; cts = (p_picture->i_pts + p_mp4->i_delay_time) * p_mp4->i_time_inc; } p_mp4->p_sample->IsRAP = p_picture->b_keyframe; p_mp4->p_sample->DTS = dts; p_mp4->p_sample->CTS_Offset = (uint32_t)(cts - dts); gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample ); p_mp4->p_sample->dataLength = 0; p_mp4->i_numframe++; return i_size; }
static GF_Err ISOW_Write(GF_StreamingCache *mc, LPNETCHANNEL ch, char *data, u32 data_size, GF_SLHeader *sl_hdr) { ISOMChannel *mch; GF_ESD *esd; u32 di, mtype; u64 DTS, CTS; ISOMReader *cache = (ISOMReader *)mc->priv; if (!cache->mov || !cache->service) return GF_BAD_PARAM; mch = isor_get_channel(cache, ch); if (!mch) { Bool mapped; GF_NetworkCommand com; com.base.on_channel = ch; com.base.command_type = GF_NET_CHAN_GET_ESD; gf_service_command(cache->service, &com, GF_OK); if (!com.cache_esd.esd) return GF_SERVICE_ERROR; esd = (GF_ESD *)com.cache_esd.esd; switch (esd->decoderConfig->streamType) { case GF_STREAM_OD: mtype = GF_ISOM_MEDIA_OD; break; case GF_STREAM_SCENE: mtype = GF_ISOM_MEDIA_SCENE; break; case GF_STREAM_VISUAL: mtype = GF_ISOM_MEDIA_VISUAL; break; case GF_STREAM_AUDIO: mtype = GF_ISOM_MEDIA_AUDIO; break; case GF_STREAM_MPEG7: mtype = GF_ISOM_MEDIA_MPEG7; break; case GF_STREAM_OCI: mtype = GF_ISOM_MEDIA_OCI; break; case GF_STREAM_IPMP: mtype = GF_ISOM_MEDIA_IPMP; break; case GF_STREAM_MPEGJ: mtype = GF_ISOM_MEDIA_MPEGJ; break; case GF_STREAM_TEXT: mtype = GF_ISOM_MEDIA_TEXT; break; default: return GF_NOT_SUPPORTED; } GF_SAFEALLOC(mch, ISOMChannel); if (!mch) { return GF_OUT_OF_MEM; } mch->time_scale = esd->slConfig->timestampResolution; mch->streamType = esd->decoderConfig->streamType; mch->track = gf_isom_new_track(cache->mov, com.cache_esd.esd->ESID, mtype, mch->time_scale); mch->is_playing = GF_TRUE; mch->channel = ch; mch->owner = cache; gf_isom_set_track_enabled(cache->mov, mch->track, 1); /*translate 3GP streams to MP4*/ mapped = GF_FALSE; if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_MEDIA_GENERIC) { char szCode[5]; strncpy(szCode, esd->decoderConfig->decoderSpecificInfo->data, 4); szCode[4]=0; if (!stricmp(szCode, "samr") || !stricmp(szCode, "amr ") || !stricmp(szCode, "sawb")) { GF_3GPConfig amrc; mapped = GF_TRUE; memset(&amrc, 0, sizeof(GF_3GPConfig)); amrc.frames_per_sample = (u32) esd->decoderConfig->decoderSpecificInfo->data[13]; amrc.type = (!stricmp(szCode, "sawb")) ? GF_ISOM_SUBTYPE_3GP_AMR_WB : GF_ISOM_SUBTYPE_3GP_AMR; amrc.vendor = GF_VENDOR_GPAC; gf_isom_3gp_config_new(cache->mov, mch->track, &amrc, NULL, NULL, &di); } else if (!stricmp(szCode, "h263")) { GF_3GPConfig h263c; memset(&h263c, 0, sizeof(GF_3GPConfig)); h263c.type = GF_ISOM_SUBTYPE_3GP_H263; h263c.vendor = GF_VENDOR_GPAC; gf_isom_3gp_config_new(cache->mov, mch->track, &h263c, NULL, NULL, &di); mapped = GF_TRUE; } } if (!mapped) gf_isom_new_mpeg4_description(cache->mov, mch->track, esd, NULL, NULL, &di); if (com.cache_esd.is_iod_stream) gf_isom_add_track_to_root_od(cache->mov, mch->track); gf_list_add(cache->channels, mch); } /*first sample, cache it*/ if (!mch->cache_sample) { mch->cache_seed_ts = sl_hdr->decodingTimeStamp; mch->cache_sample = gf_isom_sample_new(); mch->cache_sample->IsRAP = sl_hdr->randomAccessPointFlag; mch->cache_sample->dataLength = data_size; mch->cache_sample->data = (char*)gf_malloc(sizeof(char)*data_size); memcpy(mch->cache_sample->data, data, sizeof(char)*data_size); return GF_OK; } /*adjust DTS/CTS*/ DTS = sl_hdr->decodingTimeStamp - mch->cache_seed_ts; if ((mch->streamType==GF_STREAM_VISUAL) && (DTS<=mch->cache_sample->DTS)) { assert(DTS>mch->prev_dts); CTS = mch->cache_sample->DTS + mch->cache_sample->CTS_Offset; mch->cache_sample->CTS_Offset = 0; /*first time, shift all CTS*/ if (!mch->frame_cts_offset) { u32 i, count = gf_isom_get_sample_count(cache->mov, mch->track); mch->frame_cts_offset = (u32) (DTS-mch->prev_dts); for (i=0; i<count; i++) { gf_isom_modify_cts_offset(cache->mov, mch->track, i+1, mch->frame_cts_offset); } mch->cache_sample->CTS_Offset += mch->frame_cts_offset; } mch->cache_sample->DTS = mch->prev_dts + mch->frame_cts_offset; mch->cache_sample->CTS_Offset += (u32) (CTS-mch->cache_sample->DTS); } /*deal with reference picture insertion: if no CTS offset and biggest CTS until now, this is a reference insertion - we must check that in order to make sure we have strictly increasing DTSs*/ if (mch->max_cts && !mch->cache_sample->CTS_Offset && (mch->cache_sample->DTS+mch->cache_sample->CTS_Offset > mch->max_cts)) { assert(mch->cache_sample->DTS > mch->prev_dts + mch->frame_cts_offset); CTS = mch->cache_sample->DTS + mch->cache_sample->CTS_Offset; mch->cache_sample->DTS = mch->prev_dts + mch->frame_cts_offset; mch->cache_sample->CTS_Offset = (u32) (CTS-mch->cache_sample->DTS); } if (mch->cache_sample->CTS_Offset) mch->max_cts = mch->cache_sample->DTS+mch->cache_sample->CTS_Offset; /*add cache*/ gf_isom_add_sample(cache->mov, mch->track, 1, mch->cache_sample); assert(!mch->prev_dts || (mch->prev_dts < mch->cache_sample->DTS)); mch->prev_dts = mch->cache_sample->DTS; mch->duration = MAX(mch->max_cts, mch->prev_dts); gf_isom_sample_del(&mch->cache_sample); /*store sample*/ mch->cache_sample = gf_isom_sample_new(); mch->cache_sample->IsRAP = sl_hdr->randomAccessPointFlag; mch->cache_sample->DTS = DTS + mch->frame_cts_offset; mch->cache_sample->CTS_Offset = (u32) (sl_hdr->compositionTimeStamp - mch->cache_seed_ts - DTS); mch->cache_sample->dataLength = data_size; mch->cache_sample->data = (char*)gf_malloc(sizeof(char)*data_size); memcpy(mch->cache_sample->data, data, sizeof(char)*data_size); return GF_OK; }
int main(int argc, char **argv) { GF_ISOFile *movie; GF_ESD *esd; GF_Err e; Double gb_size = 5.0; u8 store_mode; u32 track, di, i, nb_samp; GF_ISOSample *samp; store_mode = GF_ISOM_OPEN_WRITE; for (i=1; i<argc; i++) { if (!strcmp(argv[i], "-flat")) store_mode = GF_ISOM_OPEN_WRITE; else if (!strcmp(argv[i], "-inter")) store_mode = GF_ISOM_WRITE_EDIT; else if (!strcmp(argv[i], "-size") && (i+1<argc)) { gb_size = atof(argv[i+1]); i++; } else if (!strcmp(argv[i], "-h")) { PrintUsage(); return 0; } } nb_samp = (u32) (gb_size*1024); fprintf(stdout, "Creating test file %s - %g GBytes - %d samples - %s mode\n", TEST_FILE_NAME, gb_size, nb_samp, (store_mode == GF_ISOM_OPEN_WRITE) ? "Flat" : "Interleaved"); movie = gf_isom_open(TEST_FILE_NAME, store_mode, NULL); if (!movie) { fprintf(stdout, "Error creating file: %s\n", gf_error_to_string(gf_isom_last_error(NULL))); return 1; } track = gf_isom_new_track(movie, 1, GF_ISOM_MEDIA_VISUAL, 25); esd = gf_odf_desc_esd_new(2); esd->decoderConfig->streamType = 4; gf_isom_new_mpeg4_description(movie, track, esd, NULL, NULL, &di); samp = gf_isom_sample_new(); samp->dataLength = 1024*1024; samp->data = gf_malloc(sizeof(char)*samp->dataLength); memset(samp->data, 0, sizeof(char)*samp->dataLength); for (i=0; i<nb_samp; i++) { if (samp->DTS % 25) samp->IsRAP = 0; else samp->IsRAP = 1; e = gf_isom_add_sample(movie, track, di, samp); samp->DTS += 1; fprintf(stdout, "Writing sample %d / %d \r", i+1, nb_samp); if (e) break; } gf_isom_sample_del(&samp); if (e) { fprintf(stdout, "\nError writing sample %d\n", i); gf_isom_delete(movie); return 1; } fprintf(stdout, "\nDone writing samples\n"); e = gf_isom_close(movie); if (e) { fprintf(stdout, "Error writing file\n"); return 1; } return 0; }