コード例 #1
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
 def _profileFromFilename(self, filename):
     result = re.match(self.profilepattern, filename)
     if result:
         debug.log("Profile=%s (filename=%s, pattern=%s)" %
                   (result.group(1), filename, self.profilepattern))
         return result.group(1)
     else:
         exit("Error: Can't extract profile from filename=%s (pattern=%s)" %
              (filename, self.profilepattern))
コード例 #2
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
 def _getStartNumberFromFilename(self, filename):
     result = re.match(self.numberpattern, filename)
     if result:
         debug.log("StartNumber=%s (filename=%s, pattern=%s)" %
                   (result.group(1), filename, self.numberpattern))
         return result.group(1)
     debug.log(
         "Warning: Can't extract start number from filename %s, using 0 (pattern=%s)"
         % (filename, self.numberpattern))
     return '0'
コード例 #3
0
ファイル: TSRemux.py プロジェクト: Eyevinn/hls-to-dash
def tsremux(tsfile, outdir, filename, starttime):
    audiofile = '%s/audio-%s' % (outdir, filename)
    videofile = '%s/video-%s' % (outdir, filename)
    debug.log("Remuxing %s to %s and %s" % (tsfile, audiofile, videofile))
    tmpaudio = tempfile.NamedTemporaryFile(dir='/tmp/', suffix='.mp4')
    tmpvideo = tempfile.NamedTemporaryFile(dir='/tmp/', suffix='.mp4')
    FFMpegCommand(tsfile, tmpaudio.name, '-y -bsf:a aac_adtstoasc -acodec copy -vn')
    FFMpegCommand(tsfile, tmpvideo.name, '-y -vcodec copy -an')
    Mp4Fragment(tmpaudio.name, audiofile, starttime)
    Mp4Fragment(tmpvideo.name, videofile, starttime)
コード例 #4
0
ファイル: TSRemux.py プロジェクト: sshaunak9/hls-to-dash
def tsremux(tsfile, outdir, filename, starttime):
    audiofile = '%s/audio-%s' % (outdir, filename)
    videofile = '%s/video-%s' % (outdir, filename)
    debug.log("Remuxing %s to %s and %s" % (tsfile, audiofile, videofile))
    tmpaudio = tempfile.NamedTemporaryFile(dir='/tmp/', suffix='.mp4')
    tmpvideo = tempfile.NamedTemporaryFile(dir='/tmp/', suffix='.mp4')
    FFMpegCommand(tsfile, tmpaudio.name,
                  '-y -bsf:a aac_adtstoasc -acodec copy -vn')
    FFMpegCommand(tsfile, tmpvideo.name, '-y -vcodec copy -an')
    Mp4Fragment(tmpaudio.name, audiofile, starttime)
    Mp4Fragment(tmpvideo.name, videofile, starttime)
コード例 #5
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
 def save(self):
     obj = {}
     obj['timebase'] = self.timebase
     if self.prevSplitTS != None:
         obj['prevsplit'] = self.prevSplitTS
     if self.nextSplitTS != None:
         obj['nextsplit'] = self.nextSplitTS
     with open(self.filename, 'w+') as f:
         f.seek(0)
         f.write(json.dumps(obj, indent=4))
         f.truncate()
     debug.log('Saved context %s to %s' % (obj, self.filename))
コード例 #6
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
 def restore(self):
     debug.log('Restoring context from %s' % self.filename)
     if os.path.isfile(self.filename):
         with open(self.filename, 'r+') as f:
             data = f.read()
             obj = json.loads(data)
             self.timebase = obj['timebase']
             if 'prevsplit' in obj:
                 self.prevSplitTS = obj['prevsplit']
             if 'nextsplit' in obj:
                 self.nextSplitTS = obj['nextsplit']
     debug.log('Context: %s' % self)
コード例 #7
0
ファイル: TSRemux.py プロジェクト: Eyevinn/hls-to-dash
def runcmd(cmd, name):
    debug.log('COMMAND: %s' % cmd)
    try:
        FNULL = open(os.devnull, 'w')
        if debug.doDebug:
            return subprocess.call(cmd)
        else:
            return subprocess.call(cmd, stdout=FNULL, stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        message = "binary tool failed with error %d" % e.returncode
        raise Exception(message)
    except OSError as e:
        raise Exception('Command %s not found, ensure that it is in your path' % name)
コード例 #8
0
ファイル: TSRemux.py プロジェクト: sshaunak9/hls-to-dash
def runcmd(cmd, name):
    debug.log('COMMAND: %s' % cmd)
    try:
        FNULL = open(os.devnull, 'w')
        if debug.doDebug:
            return subprocess.call(cmd)
        else:
            return subprocess.call(cmd, stdout=FNULL, stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        message = "binary tool failed with error %d" % e.returncode
        raise Exception(message)
    except OSError as e:
        raise Exception(
            'Command %s not found, ensure that it is in your path' % name)
コード例 #9
0
ファイル: MPD.py プロジェクト: sshaunak9/hls-to-dash
 def _parseMaster(self, variant):
     debug.log("Parsing master playlist")
     for playlist in variant.playlists:
         stream = playlist.stream_info
         (video_codec, audio_codec) = stream.codecs.split(',')
         profile = self._profileFromFilename(playlist.uri)
         profilemetadata = {
             'profile': profile,
             'videocodec': video_codec,
             'audiocodec': audio_codec,
             'stream': stream
         }
         self.profiles.append(profilemetadata)
     self._initiatePeriod(self.getPeriod(self.currentPeriodIdx),
                          self.profiles)
コード例 #10
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
 def load(self):
     self.context.restore()
     debug.log("Loading playlist: ", self.playlistlocator)
     m3u8_obj = m3u8.load(self.playlistlocator)
     if m3u8_obj.is_variant:
         if m3u8_obj.playlist_type == "VOD":
             raise Exception("VOD playlists not yet supported")
         self._parseMaster(m3u8_obj)
     else:
         raise Exception(
             "Can only create DASH manifest from an HLS master playlist")
     p = m3u8_obj.playlists[0]
     debug.log("Loading playlist: ", self.baseurl + p.uri)
     self._parsePlaylist(m3u8.load(self.baseurl + p.uri))
     for per in self.getAllPeriods():
         debug.log("Audio: ", per.as_audio)
         debug.log("Video: ", per.as_video)
     self.context.save()
コード例 #11
0
ファイル: MPD.py プロジェクト: Brainiarc7/hls-to-dash
    def _parsePlaylist(self, playlist):
        debug.log("Splicing enabled=%s" % self.splitperiod)
        self.maxSegmentDuration = playlist.target_duration
        isFirstInPeriod = True
        isFirst = True
        doSplit = False
        eventid = 1
        offset = 0.0
        state = 'initial'
        isFirstSplit = True
        lastnumber = None
        periodid = 'UNDEF'
        for seg in playlist.segments:
            if state == 'initial':
                if seg.cue_out == True:
                    state = 'insidecue'
                else:
                    state = 'outsidecue'
            elif state == 'outsidecue':
                if seg.cue_out == True:
                    state = 'insidecue'
                    if not isFirst:
                        doSplit = True
            elif state == 'insidecue':
                if seg.cue_out == False:
                    state = 'outsidecue'
                    if not isFirst:
                        doSplit = True
            #debug.log("[%s][P%d]: %s" % (state, self.currentPeriodIdx, seg.uri))

            if self.splitperiod and doSplit:
                debug.log("-- Split period before %s" % seg.uri)
                self.currentPeriodIdx = self.currentPeriodIdx + 1
                newperiod = Period("P%s" %
                                   self._getStartNumberFromFilename(seg.uri))
                self._initiatePeriod(newperiod, self.profiles)
                self.appendPeriod(newperiod)
                isFirstInPeriod = True
                doSplit = False
            duration = float(seg.duration)
            videoseg = MPDRepresentation.Segment(duration, isFirstInPeriod)
            audioseg = MPDRepresentation.Segment(duration, isFirstInPeriod)
            period = self.getPeriod(self.currentPeriodIdx)
            period.getAdaptationSetVideo().addSegment(videoseg)
            period.getAdaptationSetAudio().addSegment(audioseg)
            period.increaseDuration(duration)
            offset += duration
            if isFirstInPeriod:
                # Add EventStream to place SCTE35 metadata
                debug.log("SCTE35:%s (%s, %s)" %
                          (seg.scte35, seg.cue_out, state))
                if state == 'insidecue' and seg.cue_out == True:
                    period.addSCTE35Splice(eventid, seg.scte35_duration,
                                           seg.scte35)
                    eventid = eventid + 1
                # Obtain the start time for the first segment in this period
                firstStartTimeInPeriod = self._getStartTimeFromFile(
                    seg.base_uri + seg.uri)
                firstStartTimeInPeriodTicks = int(
                    float(firstStartTimeInPeriod) * self.context.getTimeBase())
                # Determine the period ID
                if isFirst == True:
                    debug.log('firstStartTimeInPeriod=%d, prevsplit=%d' %
                              (firstStartTimeInPeriodTicks,
                               self.context.getPrevSplit()))
                    # Store the first segment start time in this manifest
                    # to be able to calculate the MPD availability start time
                    self.firstSegmentStartTime = firstStartTimeInPeriod
                    # As this is the very first period and we then need to determine
                    # whether the first segment belongs to a period created
                    # in previous manifest so the correct period id is set
                    if self.context.getPrevSplit() == 0:
                        # We have no information of previous split so use
                        # the start time in this period as period id
                        # and save it for later use
                        self.context.setPrevSplit(firstStartTimeInPeriod)
                        periodid = self.context.getPrevSplit()
                    elif firstStartTimeInPeriodTicks < 0:
                        # Start time for a segment can actually be negative. No
                        # good way to handle it but as long as it is increasing
                        # it will eventually be back to normal
                        periodid = firstStartTimeInPeriodTicks
                        self.context.setPrevSplit(firstStartTimeInPeriod)
                    elif firstStartTimeInPeriodTicks >= self.context.getPrevSplit(
                    ):
                        if self.context.getNextSplit() == 0:
                            periodid = self.context.getPrevSplit()
                        elif firstStartTimeInPeriodTicks < self.context.getNextSplit(
                        ):
                            # Start time for the first segment in this period
                            # is still before the next split and we should use
                            # period id belonging to previous manifest
                            periodid = self.context.getPrevSplit()
                        else:
                            # Start time for the first segment in this period
                            # belongs to a new period unless this is the only period
                            # in this manifest and is actually the last split
                            if self.context.getNextSplit(
                            ) < self.context.getPrevSplit():
                                period = self.context.getPrevSplit()
                            else:
                                periodid = firstStartTimeInPeriodTicks
                                self.context.setPrevSplit(
                                    firstStartTimeInPeriod)
                    elif firstStartTimeInPeriodTicks < self.context.getPrevSplit(
                    ):
                        # If start time of first segment is smaller than ts of
                        # last split a segment time stamp reset / overflow must have
                        # occured
                        periodid = firstStartTimeInPeriodTicks
                        self.context.setPrevSplit(firstStartTimeInPeriod)
                else:
                    # Start time for the first segment in this period after a split
                    # is the period id
                    periodid = firstStartTimeInPeriodTicks
                    if isFirstSplit == True:
                        # Save the segment start time for the first split
                        self.context.setNextSplit(firstStartTimeInPeriod)
                        isFirstSplit = False
                period.setPeriodId(periodid)
                # Set period start time
                periodstartsec = float(periodid / self.context.getTimeBase())
                period.setPeriodStart(periodstartsec)
                # Set segment start time and start number for the video and audio segments
                videoseg.setStartTime(firstStartTimeInPeriod)
                audioseg.setStartTime(firstStartTimeInPeriod)
                as_audio = period.getAdaptationSetAudio()
                as_video = period.getAdaptationSetVideo()
                as_video.setStartNumber(
                    self._getStartNumberFromFilename(seg.uri))
                as_video.setStartTime(periodstartsec)
                as_audio.setStartNumber(
                    self._getStartNumberFromFilename(seg.uri))
                as_audio.setStartTime(periodstartsec)
            isFirstInPeriod = False
            isFirst = False
        if self.context.getNextSplit() < self.context.getPrevSplit():
            # No new split in this manifest, last split is the current one
            self.context.resetNextSplit()
        allperiods = self.getAllPeriods()
        lastperiod = allperiods[len(allperiods) - 1]
        lastperiod.setAsLastPeriod()