예제 #1
0
	def __init__(self, filename):
		if(filename[0] != '/'):
			Log.w(TAG, "Filename is not absolute, this may cause issues dispatching jobs.")
		ffprobe = subprocess.Popen(["ffprobe","-v", "quiet", "-print_format", "json", "-show_format", "-show_streams",filename], stdout=subprocess.PIPE)
		#Get everything from stdout once ffprobe exits, and
		try:
			ffprobe_string = ffprobe.communicate()[0]
			self.ffprobe_dict=json.loads(ffprobe_string)
		except ValueError:
			Log.e(TAG, "File could not be read, are you sure it exists?")
		ffmpeg_interlace = subprocess.Popen(["ffmpeg", "-filter:v", "idet", "-frames:v", "400", "-an", "-f", "null", "-", "-i", filename],stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		interlaced_details = ffmpeg_interlace.communicate()[1]
		interlaced_lines = interlaced_details.split("\n")
		num_progressive = 0
		for line in interlaced_lines:
			if line.find("idet") != -1 and line.find("Progressive") != -1:
				#find the number of progressive frames in this line.
				nframes = line.split("Progressive:")[1].split("Undetermined")[0]
				num_progressive = num_progressive + int(nframes)
		if num_progressive < 20:
			self.is_interlaced = True
		self.video_stream = self.parse_video(self.ffprobe_dict)
		self.audio_streams = self.parse_audio(self.ffprobe_dict)
		self.sub_streams = self.parse_subs(self.ffprobe_dict)
		self.file_format = self.ffprobe_dict["format"]["format_name"]
		self.duration = float(self.ffprobe_dict["format"]["duration"])
예제 #2
0
	def parse_video(self, ffprobe_dict):
		if ffprobe_dict == False:
			return

		foundVideo = False
		video_stream = {}
		for stream in ffprobe_dict["streams"]:
			if stream["codec_type"] == "video":
				if foundVideo:
					Log.w(TAG, "File had more than one video stream. Using the first one. This is unsupported!")
				foundVideo = True
				video_stream = {"index": stream["index"], "width": stream["width"], "height": stream["height"], "codec": stream["codec_name"] }
		return video_stream
예제 #3
0
    def parse_video(self, ffprobe_dict):
        if ffprobe_dict == False:
            return

        foundVideo = False
        video_stream = {}
        for stream in ffprobe_dict["streams"]:
            if stream["codec_type"] == "video":
                if foundVideo:
                    Log.w(
                        TAG,
                        "File had more than one video stream. Using the first one. This is unsupported!"
                    )
                foundVideo = True
                video_stream = {
                    "index": stream["index"],
                    "width": stream["width"],
                    "height": stream["height"],
                    "codec": stream["codec_name"]
                }
        return video_stream
예제 #4
0
 def __init__(self, filename):
     if (filename[0] != '/'):
         Log.w(
             TAG,
             "Filename is not absolute, this may cause issues dispatching jobs."
         )
     ffprobe = subprocess.Popen([
         "ffprobe", "-v", "quiet", "-print_format", "json", "-show_format",
         "-show_streams", filename
     ],
                                stdout=subprocess.PIPE)
     #Get everything from stdout once ffprobe exits, and
     try:
         ffprobe_string = ffprobe.communicate()[0]
         self.ffprobe_dict = json.loads(ffprobe_string)
     except ValueError:
         Log.e(TAG, "File could not be read, are you sure it exists?")
     ffmpeg_interlace = subprocess.Popen([
         "ffmpeg", "-filter:v", "idet", "-frames:v", "400", "-an", "-f",
         "null", "-", "-i", filename
     ],
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE)
     interlaced_details = ffmpeg_interlace.communicate()[1]
     interlaced_lines = interlaced_details.split("\n")
     num_progressive = 0
     for line in interlaced_lines:
         if line.find("idet") != -1 and line.find("Progressive") != -1:
             #find the number of progressive frames in this line.
             nframes = line.split("Progressive:")[1].split(
                 "Undetermined")[0]
             num_progressive = num_progressive + int(nframes)
     if num_progressive < 20:
         self.is_interlaced = True
     self.video_stream = self.parse_video(self.ffprobe_dict)
     self.audio_streams = self.parse_audio(self.ffprobe_dict)
     self.sub_streams = self.parse_subs(self.ffprobe_dict)
     self.file_format = self.ffprobe_dict["format"]["format_name"]
     self.duration = float(self.ffprobe_dict["format"]["duration"])
예제 #5
0
def media_transform(parser, options):

    #keep track if we do anything other than copying
    tcodeVideo = False
    tcodeAudio = False
    # Start with the video.
    # We're going to check the parser video_stream and compare it to our target.
    cstream = parser.video_stream
    voptions = options["video"]

    codec = "copy"
    if cstream["codec"] != voptions["codec"] or voptions["force"] == True:
        if voptions["allowhevc"] == True and cstream["codec"] == "hevc":
            Log.i(TAG, "Skipping transcode for HVEC as per override.")
        else:
            tcodeVideo = True
            Log.i(TAG, "Transcoding video track")
            codec = voptions["codec"]
    else:
        Log.i(TAG, "Copying video track")

    deinterlace = False
    if (parser.is_interlaced and voptions["deinterlace"]
            == "yes") or voptions["deinterlace"] == "forced":
        Log.i(TAG, "Deinterlacing video track (will cause transcode!)")
        tcodeVideo = True
        codec = voptions["codec"]
        deinterlace = True

    scaleopts = False

    if voptions["res"] != "keep":
        dres = 0
        if voptions["res"] == "1080p":
            dres = 1080
        elif voptions["res"] == "720p":
            dres = 720
        elif voptions["res"] == "480p":
            dres = 480

        if (cstream["height"] < dres):
            scaleopts = False
        elif (abs(cstream["height"] - dres) < 30):
            scaleopts = False
        else:
            Log.i(TAG, "Scaling video (will cause transcode!)")
            codec = voptions["codec"]
            scaleopts = dres
    bit10 = False
    if "10bit" in voptions:
        bit10 = voptions["10bit"]
    video_build = {
        "type": "video",
        "index": cstream["index"],
        "codec": codec,
        "quality": voptions["quality"],
        "deinterlacing": deinterlace,
        "scaleopts": scaleopts,
        "10bit": bit10
    }
    if options["video"]["ignore"] == True:
        Log.w(TAG, "Ignoring incorrect video codec")
        video_build = {
            "type": "video",
            "index": cstream["index"],
            "codec": "copy",
            "quality": "10",
            "deinterlacing": False,
            "scaleopts": False
        }

    aoptions = options["audio"]

    audio_building = []

    surround_exists = False
    stereo_exists = False
    #Now the hard part. Figuring out the mess of audio streams
    #Find the master track. This is the highest bitrate, highest number of channels stream, which is also in the right language.
    audio_master = {"channels": 0, 'language': 'und'}
    audio_stereo = None

    ignore_language = False
    valid_laguages = ["eng"]

    if "lang" in aoptions:
        if "ignore" in aoptions["lang"] and aoptions["lang"]["ignore"] == True:
            ignore_language = True
        if "allowed" in aoptions["lang"]:
            valid_languages = aoptions["lang"]["allowed"]

    #this feels naieve. Take a closer look at this!
    for track in parser.audio_streams:

        if ignore_language or (track["language"] in valid_languages
                               or track["language"] == "und"
                               or track["language"] == None):
            if track["channels"] > audio_master["channels"]:
                audio_master = track
            if track["channels"] < 6:
                audio_stereo = track
                stereo_exists = True
    if audio_master["channels"] > 2:
        surround_exists = True

    #Add our audio channels.
    #Use the existing surround track
    if surround_exists and aoptions["surround"]["keep"] == True:
        audio_building.append({
            "type": "audio",
            "index": audio_master["index"],
            "codec": "copy",
            "ffprocdown": False,
            "downconvert": False
        })
        Log.i(TAG, "Copying surround audio")

    #Use our existing stereo track.
    if stereo_exists and aoptions["stereo"]["keep"] == True:
        if "aac" == audio_stereo["codec"]:
            Log.i(TAG, "Copying stereo audio")
            audio_building.append({
                "type": "audio",
                "index": audio_stereo["index"],
                "codec": "copy",
                "ffprocdown": False,
                "downconvert": False
            })
        else:
            tcodeAudio = True
            Log.i(TAG, "Transcoding existing stereo audio")
            audio_building.append({
                "type":
                "audio",
                "index":
                audio_stereo["index"],
                "codec":
                "aac",
                "bitrate":
                aoptions["stereo"]["bitrate"],
                "downconvert":
                False,
                "forcefdk":
                aoptions["stereo"]["force_libfdk"],
                "ffprocdown":
                False
            })

    #Create from surround.
    if surround_exists and (not stereo_exists or aoptions["stereo"]["keep"]
                            == False) and aoptions["stereo"]["create"] == True:
        Log.i(TAG, "Downmixing surround to stereo")
        tcodeAudio = True
        audio_building.append({
            "type":
            "audio",
            "index":
            audio_master["index"],
            "codec":
            "aac",
            "bitrate":
            aoptions["stereo"]["bitrate"],
            "downconvert":
            True,
            "forcefdk":
            aoptions["stereo"]["force_libfdk"],
            "ffprocdown":
            aoptions["stereo"]["ffproc_filtering"]
        })

    #Are we doing any transcoding?
    tcode = tcodeVideo or tcodeAudio

    remux = False
    if not tcode and parser.file_format.find(
            options["format"]["filetype"]) == -1:
        remux = True

    audio_building.append(video_build)
    return {
        "video": tcodeVideo,
        "audio": tcodeAudio,
        "remux": remux,
        "tcodeData": audio_building
    }
예제 #6
0
def media_transform(parser, options):

	#keep track if we do anything other than copying
	tcodeVideo=False
	tcodeAudio=False
	# Start with the video.
	# We're going to check the parser video_stream and compare it to our target.
	cstream = parser.video_stream
	voptions = options["video"]

	codec = "copy"
	if cstream["codec"] != voptions["codec"] or voptions["force"] == True:
		if voptions["allowhevc"] == True and cstream["codec"] == "hevc":
			Log.i(TAG, "Skipping transcode for HVEC as per override.")
		else:
			tcodeVideo = True
			Log.i(TAG, "Transcoding video track")
			codec = voptions["codec"]
	else:
		Log.i(TAG, "Copying video track")

	deinterlace = False
	if (parser.is_interlaced and voptions["deinterlace"] == "yes") or voptions["deinterlace"] == "forced":
		Log.i(TAG, "Deinterlacing video track (will cause transcode!)")
		tcodeVideo=True
		codec = voptions["codec"]
		deinterlace = True

	scaleopts = False

	if voptions["res"] != "keep":
		dres = 0
		if voptions["res"] == "1080p":
			dres = 1080
		elif voptions["res"] == "720p":
			dres = 720
		elif voptions["res"] == "480p":
			dres = 480

		if(cstream["height"] < dres):
			scaleopts = False
		elif(abs(cstream["height"] - dres) < 30):
			scaleopts = False
		else:
			Log.i(TAG, "Scaling video (will cause transcode!)")
			codec = voptions["codec"]
			scaleopts = dres

	video_build = {"type":"video", "index":cstream["index"], "codec": codec, "quality": voptions["quality"], "deinterlacing": deinterlace, "scaleopts": scaleopts}
	if options["video"]["ignore"] == True:
		Log.w(TAG, "Ignoring incorrect video codec")
		video_build = {"type":"video", "index":cstream["index"], "codec": "copy", "quality": "10", "deinterlacing": False, "scaleopts": False}

	aoptions = options["audio"]

	audio_building=[]

	surround_exists = False
	stereo_exists = False
	#Now the hard part. Figuring out the mess of audio streams
	#Find the master track. This is the highest bitrate, highest number of channels stream, which is also in the right language.
	audio_master = {"channels": 0, 'language':'und'}
	audio_stereo = None

	#this feels naieve. Take a closer look at this!
	for track in parser.audio_streams:

		if ( track["language"] == "eng" or track["language"] == "und" or track["language"] == None):
			if track["channels"] > audio_master["channels"]:
				audio_master = track
			if track["channels"] < 6:
				audio_stereo = track
				stereo_exists = True
	if audio_master["channels"] > 2:
		surround_exists = True

	#Add our audio channels.
	#Use the existing surround track
	if surround_exists and aoptions["surround"]["keep"] == True:
		audio_building.append({"type":"audio","index":audio_master["index"], "codec": "copy","ffprocdown":False,"downconvert":False})
		Log.i(TAG, "Copying surround audio")

	#Use our existing stereo track.
	if stereo_exists and aoptions["stereo"]["keep"] == True:
		if "aac" == audio_stereo["codec"]:
			Log.i(TAG, "Copying stereo audio")
			audio_building.append({"type":"audio","index":audio_stereo["index"], "codec": "copy","ffprocdown":False,"downconvert":False})
		else:
			tcodeAudio = True
			Log.i(TAG, "Transcoding existing stereo audio")
			audio_building.append({"type":"audio","index":audio_master["index"], "codec": "aac", "bitrate": aoptions["stereo"]["bitrate"],"downconvert":False, "forcefdk":aoptions["stereo"]["force_libfdk"],"ffprocdown":False})

	#Create from surround.
	if surround_exists and (not stereo_exists or aoptions["stereo"]["keep"] == False) and aoptions["stereo"]["create"] == True:
		Log.i(TAG, "Downmixing surround to stereo")
		tcodeAudio = True
		audio_building.append({"type":"audio","index":audio_master["index"], "codec": "aac", "bitrate": aoptions["stereo"]["bitrate"],"downconvert":True, "forcefdk":aoptions["stereo"]["force_libfdk"],"ffprocdown":aoptions["stereo"]["ffproc_filtering"]})
	
	#Are we doing any transcoding?
	tcode = tcodeVideo or tcodeAudio

	remux = False
	if not tcode and parser.file_format.find(options["format"]["filetype"]) == -1:
		remux = True

	audio_building.append(video_build)
	return {"video": tcodeVideo, "audio": tcodeAudio, "remux": remux, "tcodeData":audio_building}