1 | # -*- coding: utf-8 -*- |
---|
2 | __author__ = 'sanmai' |
---|
3 | |
---|
4 | import subprocess |
---|
5 | import os |
---|
6 | import tempfile |
---|
7 | import pprint |
---|
8 | import logging |
---|
9 | |
---|
10 | logger = logging.getLogger('waitress') |
---|
11 | |
---|
12 | |
---|
13 | def get_full_ffmpeg_command(ffmpeg_command, input_mime_type, output_mime_type, output_media_file_path): |
---|
14 | full_ffmpeg_command = None |
---|
15 | |
---|
16 | if input_mime_type == "audio/x-wav" and output_mime_type == "audio/mp4": |
---|
17 | full_ffmpeg_command = [ffmpeg_command, |
---|
18 | "-i", "pipe:0", |
---|
19 | "-c:a", "libfdk_aac", |
---|
20 | "-b:a", "128k", |
---|
21 | "-nostdin", "-y", |
---|
22 | output_media_file_path] |
---|
23 | |
---|
24 | if full_ffmpeg_command is not None: |
---|
25 | logger.debug("Full ffmpeg command: " + " ".join(full_ffmpeg_command)) |
---|
26 | |
---|
27 | return full_ffmpeg_command |
---|
28 | else: |
---|
29 | raise NotImplementedError() |
---|
30 | |
---|
31 | |
---|
32 | def convert(input_media_data, |
---|
33 | input_mime_type, |
---|
34 | output_mime_type, |
---|
35 | temp_directory_path, |
---|
36 | ffmpeg_command): |
---|
37 | try: |
---|
38 | output_media_file_fd, output_media_file_path = tempfile.mkstemp(dir=temp_directory_path, |
---|
39 | suffix=".m4a") |
---|
40 | os.close(output_media_file_fd) |
---|
41 | |
---|
42 | try: |
---|
43 | full_ffmpeg_command = get_full_ffmpeg_command(ffmpeg_command, |
---|
44 | input_mime_type, |
---|
45 | output_mime_type, |
---|
46 | output_media_file_path) |
---|
47 | |
---|
48 | process = subprocess.Popen(full_ffmpeg_command, |
---|
49 | stdin=subprocess.PIPE, |
---|
50 | stdout=subprocess.DEVNULL, |
---|
51 | stderr=subprocess.DEVNULL, |
---|
52 | shell=False, |
---|
53 | close_fds=True, |
---|
54 | universal_newlines=False) |
---|
55 | except OSError as e: |
---|
56 | logger.error("ffmpeg could not be launched. " + pprint.pprint(e)) |
---|
57 | raise |
---|
58 | else: |
---|
59 | try: |
---|
60 | process.stdin.write(input_media_data) |
---|
61 | process.stdin.flush() |
---|
62 | process.stdin.close() |
---|
63 | process.wait(timeout=180) |
---|
64 | |
---|
65 | except subprocess.TimeoutExpired as e: |
---|
66 | process.kill() |
---|
67 | logger.error("ffmpeg process timed out. " + pprint.pprint(e)) |
---|
68 | raise |
---|
69 | else: |
---|
70 | try: |
---|
71 | with open(output_media_file_path, |
---|
72 | 'rb') as output_media_file: |
---|
73 | output_media_file_data = output_media_file.read() |
---|
74 | |
---|
75 | try: |
---|
76 | if output_media_file_data is None: |
---|
77 | raise ChildProcessError() |
---|
78 | except ChildProcessError as e: |
---|
79 | logger.error("Output media file at '{0}' is empty. " |
---|
80 | .format(output_media_file_path) + pprint.pprint(e)) |
---|
81 | raise |
---|
82 | else: |
---|
83 | try: |
---|
84 | os.remove(output_media_file_path) |
---|
85 | except OSError as e: |
---|
86 | logger.error("Output media file at '{0}' could not be deleted after ffmpeg process. " |
---|
87 | .format(output_media_file_path) + pprint.pprint(e)) |
---|
88 | raise |
---|
89 | else: |
---|
90 | logger.debug("Successful conversion from '{0}' to '{1}'. " |
---|
91 | .format(input_mime_type, output_mime_type)) |
---|
92 | return output_media_file_data |
---|
93 | except OSError as e: |
---|
94 | logger.error("Output media file at '{0}' could not be read after ffmpeg process. " |
---|
95 | .format(output_media_file_path) + pprint.pprint(e)) |
---|
96 | raise |
---|
97 | except Exception as e: |
---|
98 | logger.error("Output media file could not be created. " + pprint.pprint(e)) |
---|
99 | raise |
---|
100 | |
---|
101 | |
---|
102 | class Converter(object): |
---|
103 | def __init__(self, |
---|
104 | caching, |
---|
105 | temp_directory_path, |
---|
106 | ffmpeg_command): |
---|
107 | |
---|
108 | self.caching = caching |
---|
109 | self.temp_directory_path = temp_directory_path |
---|
110 | self.ffmpeg_command = ffmpeg_command |
---|
111 | |
---|
112 | if self.caching: |
---|
113 | import media_conv.cache |
---|
114 | |
---|
115 | def convert_media_file(self, |
---|
116 | input_media_data, |
---|
117 | input_mime_type, |
---|
118 | output_mime_type): |
---|
119 | if self.caching: |
---|
120 | logger.info("Caching is enabled. ") |
---|
121 | raise NotImplementedError() |
---|
122 | else: |
---|
123 | output_media_data = convert(input_media_data=input_media_data, |
---|
124 | input_mime_type=input_mime_type, |
---|
125 | output_mime_type=output_mime_type, |
---|
126 | temp_directory_path=self.temp_directory_path, |
---|
127 | ffmpeg_command=self.ffmpeg_command) |
---|
128 | |
---|
129 | return output_media_data |
---|