data.setdefault('max_movie_time', 0)
data.setdefault('ffmpeg_output_movies', False)
if motionctl.has_new_movie_format_support():
- data.setdefault('ffmpeg_video_codec', 'mp4') # will use h264 codec
+ if motionctl.has_h264_omx_support():
+ data.setdefault('ffmpeg_video_codec', 'mp4:h264_omx') # will use h264 codec
+
+ else:
+ data.setdefault('ffmpeg_video_codec', 'mp4') # will use h264 codec
+
if motionctl.needs_ffvb_quirks():
data.setdefault('ffmpeg_variable_bitrate', _MAX_FFMPEG_VARIABLE_BITRATE / 4) # 75%
admin_username=config.get_main().get('@admin_username'),
has_streaming_auth=motionctl.has_streaming_auth(),
has_new_movie_format_support=motionctl.has_new_movie_format_support(),
+ has_h264_omx_support=motionctl.has_h264_omx_support(),
has_motion=bool(motionctl.find_motion()[0]),
mask_width=utils.MASK_WIDTH)
'mov': 'mpeg4',
'mp4': 'h264',
'mkv': 'h264',
+ 'mp4:h264_omx': 'h264_omx',
+ 'mkv:h264_omx': 'h264_omx',
'hevc': 'h265'
}
_timelapse_process = None
_timelapse_data = None
+_ffmpeg_binary_cache = None
+
def findfiles(path):
files = []
def find_ffmpeg():
+ global _ffmpeg_binary_cache
+ if _ffmpeg_binary_cache:
+ return _ffmpeg_binary_cache
+
+ # binary
try:
- return subprocess.check_output(['which', 'ffmpeg'], stderr=utils.DEV_NULL).strip()
+ binary = subprocess.check_output(['which', 'ffmpeg'], stderr=utils.DEV_NULL).strip()
except subprocess.CalledProcessError: # not found
- return None
+ return None, None, None
+
+ # version
+ try:
+ output = subprocess.check_output(binary + ' -version', shell=True)
+
+ except subprocess.CalledProcessError as e:
+ logging.error('ffmpeg: could find version: %s' % e)
+ return None, None, None
+
+ result = re.findall('ffmpeg version (.+?) ', output, re.IGNORECASE)
+ version = result and result[0] or ''
+
+ # codecs
+ try:
+ output = subprocess.check_output(binary + ' -codecs -hide_banner', shell=True)
+
+ except subprocess.CalledProcessError as e:
+ logging.error('ffmpeg: could not list supported codecs: %s' % e)
+ return None, None, None
+
+ lines = output.split('\n')
+ matches = [re.match('^ [DEVILSA.]{6} ([\w+_]+) ', l) for l in lines]
+ codecs = set([m.group(1) for m in matches if m])
+
+ logging.debug('using ffmpeg version %s' % version)
+
+ _ffmpeg_binary_cache = (binary, version, codecs)
+
+ return _ffmpeg_binary_cache
def cleanup_media(media_type):
from tornado.ioloop import IOLoop
+import mediafiles
import powerctl
import settings
import update
program, version = program # @UnusedVariable
- logging.debug('using motion binary "%s"' % program)
+ logging.debug('starting motion binary "%s"' % program)
motion_config_path = os.path.join(settings.CONF_PATH, 'motion.conf')
motion_log_path = os.path.join(settings.LOG_PATH, 'motion.log')
return version.lower().count('git') or update.compare_versions(version, '3.4') >= 0
+def has_h264_omx_support():
+ binary, version, codecs = mediafiles.find_ffmpeg()
+ if not binary:
+ return False
+
+ # TODO also check for motion codec parameter support
+
+ return 'h264_omx' in codecs
+
+
def get_rtsp_support():
binary, version = find_motion()
if not binary:
<option value="mov">QuickTime (.mov)</option>
{% if has_new_movie_format_support %}
<option value="mp4">H.264 (.mp4)</option>
+ {% if has_h264_omx_support %}
+ <option value="mp4:h264_omx">H.264/OMX (.mp4)</option>
+ {% endif %}
<option value="hevc">HEVC (.mp4)</option>
<option value="mkv">Matroska Video (.mkv)</option>
+ {% if has_h264_omx_support %}
+ <option value="mkv:h264_omx">Matroska Video/OMX (.mkv)</option>
+ {% endif %}
{% endif %}
</select>
</td>