FFmpeg python 不合并

问题描述

我用 Python 制作了这个 youtube 下载器 GUI:它要求提供 URL,为您提供一个包含可能的质量设置的列表,并使用 youtube-dl 下载选定的视频文件和最佳音频文件。但是,当我告诉 ffmpeg 合并两个单独下载的文件时,它什么也没做,也没有在控制台中说什么。有什么我遗漏的吗?

这是代码的相关部分(从第 153 行开始):

            #Adding input arguments for ffmpeg
            ffmpeg_video = ffmpeg.input(self.video_title)
            ffmpeg_audio = ffmpeg.input(self.audio_title)
            output_ffmpeg_title = './videos/' + self.youtube_title
            #Merging with ffmpeg
            out = ffmpeg.output(ffmpeg_video,ffmpeg_audio,output_ffmpeg_title,vcodec='copy',acodec='aac')
            out.run

完整代码如下:

import youtube_dl
import tkinter as tk
import operator
import ffmpeg
class GUI:
    def __init__(self):
        #Creating initial window
        self.window = tk.Tk()
        self.window.title('YTDL')
        self.window.geometry('300x70')
        
        self.urlBox = tk.Entry(self.window)
        self.urlBox.pack(padx=5,pady=5)
        #Creating download button,which will open the format selection window
        downbutton = tk.Button(self.window,text="Download",command= self.check_url)
        downbutton.pack(padx=5,pady=5)
        #Creating a variable to keep track of the point in the GUI options selection
        self.format_select_process = False
        
        self.window.mainloop()
    def check_url(self):
        #Saving selected URL to variable
        self.selected_url = self.urlBox.get()
        self.urlBox.delete(0,'end')
        #If something was written in the URL Box,try to go the next step
        if len(self.selected_url) != 0:
            self.get_formats(self.selected_url)
        else:
            print('URL Box is empty!')
    def get_formats(self,x):
        with youtube_dl.YoutubedL() as ydl:
            Meta = ydl.extract_info(x,download=False)
            #Save formats from 'Meta' to 'self.formats'
            self.formats = Meta.get('formats',[Meta])
            self.youtube_title = Meta.get('title',[Meta])
            #Creating two dictionaries for the list of format sizes and extensions
            self.f_list_size_dict = {}
            self.f_list_ext_dict = {}
            #Creating audio format list
            self.audio_format_list = []
        #For every format in self.formats,add its format,extension,fps and filesize to self.f_list
        for f in self.formats:
            self.f_list = '-' + f['format']+ ' -' + f['ext'] + ' -' + str(f['fps']) + ' ' + str(f['filesize'])
            if 'audio only' in f['format']:
                #Add an element to each dictonary whose name is the format ID and whose value is its filesize/extension
                self.f_list_size_dict[f['format'].split(' -')[0]] = f['filesize']
                self.f_list_ext_dict[f['format'].split(' -')[0]] = f['ext']
                #Add to the audio format list the current audio format ID
                self.audio_format_list.append(f['format'].split(' -')[0])
        print('Audio format list:')
        print(self.audio_format_list)
        print('Size list dict:')
        print(self.f_list_size_dict)
        print('Ext list size dict:')
        print(self.f_list_ext_dict)
        """
        #Making a new list which only contains the audio format IDs
        self.audio_format_list = str(self.f_list_size_dict.keys()).split('([')[1]
        self.audio_format_list = self.audio_format_list.split('])')[0]
        self.audio_format_list = self.audio_format_list.replace("'","")
        self.audio_format_list = self.audio_format_list.split(',')
        print('Cleaned up audio format list:')
        print(self.audio_format_list)
        """
        #Here the program starts looking for the best audio format
        #In the try block,the program gets the best audio format's ID from the size dict and extension from the ext dict
        #In the except block,the program gets the ID from the audio format list and the extension from the ext dict
        try:
            self.highest_audio = max(self.f_list_size_dict.items(),key=operator.itemgetter(1))[0]
            self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
            print('Best audio format ID: ' + self.highest_audio)
            print('Best audio format extension: ' + self.highest_audio_ext)
        except:
            self.highest_audio = max(self.audio_format_list)
            self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
            print(self.highest_audio)
            print(self.highest_audio_ext)
        #Going to next sted of the code,which renders the format choice window
        self.format_select()
    def format_select(self):
        self.window.withdraw()
        format_select_window = tk.Toplevel()
        format_select_window.attributes('-topmost',True)
        format_select_window.geometry("300x350")
        format_select_window_label = tk.Label(format_select_window,text="Select the video format")
        format_select_window_label.pack(padx=5,pady=5)
        format_select_window.protocol('WM_DELETE_WINDOW',lambda: exit())

        self.format_listBox = tk.ListBox(format_select_window,height=15,width=40,yscrollcommand=1)
        self.format_listBox.pack(padx=10,pady=10)
        for index,item in enumerate(self.f_list):
            self.f_list_lenght = index
        download_button = tk.Button(format_select_window,text='Download',command=self.download)
        download_button.pack(padx=10,pady=10)
        #Adding options to the listBox
        for f in self.formats:
            #If it is adding an audio only format,it will add the ID,filesize (if possible with try block) and extension
            if 'audio only' in f['format'] + ' ' + str(f['fps']) + ' FPS ' + f['ext']:
                try:
                    mb_filesize = round(f['filesize'] / 1024 / 1024,2)
                    self.format_listBox.insert(self.f_list_lenght,f['format'] + ' ' + str(mb_filesize) + ' MiB  ' + f['ext']) 
                except:
                    self.format_listBox.insert(self.f_list_lenght,f['format'] + '  ' + f['ext'])
            #If it is adding a video format,FPS,filesize (if possible with the try block) and extension
            else:
                try:
                    mb_filesize = round(f['filesize'] / 1024 / 1024,f['format'] + ' ' + str(f['fps']) + ' FPS' + ' ' + str(mb_filesize) + ' MiB  ' + f['ext'])
                except:
                    self.format_listBox.insert(self.f_list_lenght,f['format'] + ' ' + str(f['fps']) + ' FPS  ' + f['ext'])
    def download(self):
        #Getting the list position of the selected format
        selected_format_list_position = self.format_listBox.curselection()
        #Getting the text of the selected format list item
        selected_format = self.format_listBox.get(selected_format_list_position)
        print('Selected format: ' + selected_format)
        #Cutting from the selected format list item text everything past ' -' to only get the format's ID
        selected_format_id = selected_format.split(' -')[0]
        print('Selected format ID: ' + selected_format_id)
        #Converting the ID to string
        final_selected_format_id = str(selected_format_id)
        print('Final selected format: ' + final_selected_format_id)
        #Cutting from the selected format list item text everything before '  ' to only get the extension
        final_ext = selected_format.split('  ')[1]
        print('Final video extension: ' + final_ext)
        if 'audio only' in selected_format:
            #Creating the download options dictionary (not working):
            #Setting the download location to the videos folder,#preventing the program from downloading a whole playlist,#telling youtube-dl to extract audio ('x'),#giving youtube-dl the requested format (which is only audio).
            self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s','noplaylist': True,'x': True,'format': final_selected_format_id}
            #Downloading
            with youtube_dl.YoutubedL(self.ydl_opts) as ydl:
                ydl.download([self.selected_url])
        elif 'audio only' not in selected_format:
            #Adding '+bestaudio' to the selected format ID (which is only a video ID in this case)
            final_selected_format_id_video_audio = str(selected_format_id) + '+bestaudio'
            #Creating the download options dictionary:
            #Setting the download location to the videos folder,#giving youtube-dl the requested format with audio.
            self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s','format': final_selected_format_id_video_audio}
            #Predicting the video file title and location for future ffmpeg merge
            self.video_title = './videos/' + self.youtube_title + '.f' + str(selected_format_id) + '.' + final_ext
            print('Video file title: ' + self.video_title)
            #Predicting the audio file title and location for future ffmpeg merge
            self.audio_title = './videos/' + self.youtube_title + '.f' + str(self.highest_audio) + '.' + self.highest_audio_ext
            print('Audio file title: ' + self.audio_title)
            #Downloading with youtube-dl
            with youtube_dl.YoutubedL(self.ydl_opts) as ydl:
                ydl.download([self.selected_url])
            #Adding input arguments for ffmpeg
            ffmpeg_video = ffmpeg.input(self.video_title)
            ffmpeg_audio = ffmpeg.input(self.audio_title)
            output_ffmpeg_title = './videos/' + self.youtube_title
            #Merging with ffmpeg
            ffmpeg.output(ffmpeg_video,acodec='aac')
GUI()

如果有更好的方法将 ffmpeg 与 Python 中的 youtube-dl 集成,请告诉我。

解决方法

  • 在您的完整代码中缺少 run() 函数。
  • 试试这个

ffmpeg.output(ffmpeg_video,ffmpeg_audio,output_ffmpeg_title,vcodec='copy',acodec='aac').run()