Recherche avancée

Médias (91)

Autres articles (90)

  • MediaSPIP version 0.1 Beta

    16 avril 2011, par

    MediaSPIP 0.1 beta est la première version de MediaSPIP décrétée comme "utilisable".
    Le fichier zip ici présent contient uniquement les sources de MediaSPIP en version standalone.
    Pour avoir une installation fonctionnelle, il est nécessaire d’installer manuellement l’ensemble des dépendances logicielles sur le serveur.
    Si vous souhaitez utiliser cette archive pour une installation en mode ferme, il vous faudra également procéder à d’autres modifications (...)

  • Amélioration de la version de base

    13 septembre 2013

    Jolie sélection multiple
    Le plugin Chosen permet d’améliorer l’ergonomie des champs de sélection multiple. Voir les deux images suivantes pour comparer.
    Il suffit pour cela d’activer le plugin Chosen (Configuration générale du site > Gestion des plugins), puis de configurer le plugin (Les squelettes > Chosen) en activant l’utilisation de Chosen dans le site public et en spécifiant les éléments de formulaires à améliorer, par exemple select[multiple] pour les listes à sélection multiple (...)

  • Support audio et vidéo HTML5

    10 avril 2011

    MediaSPIP utilise les balises HTML5 video et audio pour la lecture de documents multimedia en profitant des dernières innovations du W3C supportées par les navigateurs modernes.
    Pour les navigateurs plus anciens, le lecteur flash Flowplayer est utilisé.
    Le lecteur HTML5 utilisé a été spécifiquement créé pour MediaSPIP : il est complètement modifiable graphiquement pour correspondre à un thème choisi.
    Ces technologies permettent de distribuer vidéo et son à la fois sur des ordinateurs conventionnels (...)

Sur d’autres sites (10669)

  • dockerized python application takes a long time to trim a video with ffmpeg

    15 avril 2024, par Ukpa Uchechi

    The project trims YouTube videos.

    


    When I ran the ffmpeg command on the terminal, it didn't take too long to respond. The code below returns the trimmed video to the front end but it takes too long to respond. A 10 mins trim length takes about 5mins to respond. I am missing something, but I can't pinpoint the issue.

    


    backend

    


    main.py

    


    import os

from flask import Flask, request, send_file
from flask_cors import CORS, cross_origin


app = Flask(__name__)
cors = CORS(app)


current_directory = os.getcwd()
folder_name = "youtube_videos"
save_path = os.path.join(current_directory, folder_name)
output_file_path = os.path.join(save_path, 'video.mp4')

os.makedirs(save_path, exist_ok=True)

def convert_time_seconds(time_str):
    hours, minutes, seconds = map(int, time_str.split(':'))
    total_seconds = (hours * 3600) + (minutes * 60) + seconds

    return total_seconds
def convert_seconds_time(total_seconds):
    new_hours = total_seconds // 3600
    total_seconds %= 3600
    new_minutes = total_seconds // 60
    new_seconds = total_seconds % 60

    new_time_str = f'{new_hours:02}:{new_minutes:02}:{new_seconds:02}'

    return new_time_str
def add_seconds_to_time(time_str, seconds_to_add):
    total_seconds = convert_time_seconds(time_str)

    total_seconds -= seconds_to_add
    new_time_str = convert_seconds_time(total_seconds)

    return new_time_str

def get_length(start_time, end_time):
    start_time_seconds = convert_time_seconds(start_time)
    end_time_seconds = convert_time_seconds(end_time)

    length = end_time_seconds - start_time_seconds

    length_str = convert_seconds_time(length)
    return length_str
    
def download_url(url):
    command = [
        "yt-dlp",
        "-g",
        url
    ]
    
    try:
        links = subprocess.run(command, capture_output=True, text=True, check=True)
        
        video, audio = links.stdout.strip().split("\n")
        
        return video, audio

    except subprocess.CalledProcessError as e:
        print(f"Command failed with return code {e.returncode}.")
        print(f"Error output: {e.stderr}")
        return None
    except ValueError:
        print("Error: Could not parse video and audio links.")
        return None
    


def download_trimmed_video(video_link, audio_link, start_time, end_time):
    new_start_time = add_seconds_to_time(start_time, 30)
    new_end_time = get_length(start_time, end_time)

    if os.path.exists(output_file_path):
        os.remove(output_file_path)


    command = [
        'ffmpeg',
        '-ss', new_start_time + '.00',
        '-i', video_link,
        '-ss', new_start_time + '.00',
        '-i', audio_link,
        '-map', '0:v',
        '-map', '1:a',
        '-ss', '30',
        '-t', new_end_time + '.00',
        '-c:v', 'libx264',
        '-c:a', 'aac',
        output_file_path
    ]
    try:
        result = subprocess.run(command, capture_output=True, text=True, check=True)

        if result.returncode == 0:
            return "Trimmed video downloaded successfully!"
        else:
            return "Error occurred while downloading trimmed video"
    except subprocess.CalledProcessError as e:
        print(f"Command failed with return code {e.returncode}.")
        print(f"Error output: {e.stderr}")


app = Flask(__name__)


@app.route('/trimvideo', methods =["POST"])
@cross_origin()
def trim_video():
    print("here")
    data = request.get_json()
    video_link, audio_link = download_url(data["url"])
    if video_link and audio_link:
        print("Downloading trimmed video...")
        download_trimmed_video(video_link, audio_link, data["start_time"], data["end_time"])
        response = send_file(output_file_path, as_attachment=True, download_name='video.mp4')
    
        response.status_code = 200

        return response
    else:
        return "Error downloading video", 400

    




if __name__ == '__main__':
    app.run(debug=True, port=5000, host='0.0.0.0')


    


    dockerfile

    


    FROM ubuntu:latest

# Update the package list and install wget and ffmpeg
RUN apt-get update \
    && apt-get install -y wget ffmpeg python3 python3-pip \
    && rm -rf /var/lib/apt/lists/*

# Download the latest version of yt-dlp and install it
RUN wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp \
    && chmod a+rx /usr/local/bin/yt-dlp

WORKDIR /app

COPY main.py /app/
COPY requirements.txt /app/


RUN pip install --no-cache-dir -r requirements.txt


# Set the default command
CMD ["python3", "main.py"]


    


    requirements.txt

    


    blinker==1.7.0
click==8.1.7
colorama==0.4.6
Flask==3.0.3
Flask-Cors==4.0.0
itsdangerous==2.1.2
Jinja2==3.1.3
MarkupSafe==2.1.5
Werkzeug==3.0.2


    


    frontend

    


    App.js

    


    &#xA;import React, { useState } from &#x27;react&#x27;;&#xA;import &#x27;./App.css&#x27;;&#xA;import axios from &#x27;axios&#x27;;&#xA;async function handleSubmit(event, url, start_time, end_time, setVideoUrl, setIsSubmitted){&#xA;  event.preventDefault();&#xA;&#xA;  if( url &amp;&amp; start_time &amp;&amp; end_time){&#xA;&#xA;    try {&#xA;      setIsSubmitted(true);&#xA;    const response = await axios.post(&#x27;http://127.0.0.1:5000/trimvideo&#x27;, {&#xA;      url: url,&#xA;      start_time: start_time,&#xA;      end_time: end_time&#xA;    },&#xA;    {&#xA;      responseType: &#x27;blob&#x27;,&#xA;      headers: {&#x27;Content-Type&#x27;: &#x27;application/json&#x27;}&#xA;    }&#xA;  )&#xA;    const blob = new Blob([response.data], { type: &#x27;video/mp4&#x27; });&#xA;    const newurl = URL.createObjectURL(blob);&#xA;&#xA;&#xA;    setVideoUrl(newurl);&#xA;    } catch (error) {&#xA;      console.error(&#x27;Error trimming video:&#x27;, error);&#xA;    }&#xA;&#xA;  } else {&#xA;    alert(&#x27;Please fill all the fields&#x27;);&#xA;  }&#xA;}&#xA;&#xA;&#xA;function App() {&#xA;  const [url, setUrl] = useState(&#x27;&#x27;);&#xA;  const [startTime, setStartTime] = useState(&#x27;&#x27;);&#xA;  const [endTime, setEndTime] = useState(&#x27;&#x27;);&#xA;  const [videoUrl, setVideoUrl] = useState(&#x27;&#x27;);&#xA;  const [isSubmitted, setIsSubmitted] = useState(false);&#xA;  return (&#xA;    <div classname="App">&#xA;        <div classname="app-header">TRIM AND DOWNLOAD YOUR YOUTUBE VIDEO HERE</div>&#xA;        <input classname="input-url" placeholder="&#x27;Enter" value="{url}" />setUrl(e.target.value)}/>&#xA;        <div classname="input-container">&#xA;          <input classname="start-time-url" placeholder="start time" value="{startTime}" />setStartTime(e.target.value)}/>&#xA;          <input classname="end-time-url" placeholder="end time" value="{endTime}" />setEndTime(e.target.value)}/>&#xA;        &#xA;        </div>&#xA;        {&#xA;          !isSubmitted &amp;&amp; <button>> handleSubmit(event, url, startTime, endTime, setVideoUrl, setIsSubmitted)} className=&#x27;trim-button&#x27;>Trim</button>&#xA;        }&#xA;&#xA;        {&#xA;         ( isSubmitted &amp;&amp; !videoUrl) &amp;&amp;   <div classname="dot-pulse"></div>&#xA;        }&#xA;&#xA;&#xA;        {&#xA;          videoUrl &amp;&amp; <video controls="controls" autoplay="autoplay" width="500" height="360">&#xA;          <source src="{videoUrl}" type="&#x27;video/mp4&#x27;"></source>&#xA;        </video>&#xA;        }&#xA;&#xA;        &#xA;    </div>&#xA;  );&#xA;}&#xA;&#xA;export default App;&#xA;

    &#xA;

  • Get the maximum frequency of an audio spectrum

    6 avril, par milahu

    I want to detect the cutoff frequency of the AAC audio encoder used to compress an M4A audio file.

    &#xA;

    This cutoff frequency (or maximum frequency) is an indicator of audio quality.&#xA;High-quality audio has a cutoff around 20KHz (fullband),&#xA;medium-quality audio has a cutoff around 14KHz (superwideband),&#xA;low-quality audio has a cutoff around 7KHz (wideband),&#xA;super-low-quality audio has a cutoff around 3KHz (narrowband).&#xA;See also : voice frequency

    &#xA;

    Example spectrum of a 2 hours movie, generated with sox, with a maximum frequency around 19.6KHz :

    &#xA;

    audio spectrum with maximum frequency around 19.6KHz

    &#xA;

    The program should ignore noise below a certain loudness, for example -80dB.

    &#xA;

    Here is a Python script generated by deepseek.com but it returns 0.2KHz instead of 19.6KHz.

    &#xA;

    #!/usr/bin/env python3&#xA;&#xA;# get the maximum frequency&#xA;# of an audio spectrum&#xA;# as an indicator&#xA;# of the actual audio quality&#xA;&#xA;# generated by deepseek.com&#xA;&#xA;# prompt&#xA;"""&#xA;create a python script&#xA;to detect the maximum frequency &#xA;in an m4a audio file.&#xA;that maximum frequency is produced&#xA;by the lowpass filter&#xA;of the aac audio encoder.&#xA;high-quality audio&#xA;has a maximum frequency&#xA;around 20 KHz (fullband),&#xA;low-quality audio&#xA;has a maximum frequency&#xA;around 3 KHz (narrowband).&#xA;use ffmpeg to decode the audio&#xA;to pcm&#xA;in chunks of 10 seconds.&#xA;for each chunk:&#xA;detect the local maximum,&#xA;print the local maximum&#xA;and the chunk time&#xA;with the format&#xA;f"t={t}sec f={f}KHz",&#xA;update the global maximum.&#xA;to detect the local maximum,&#xA;remove the noise floor&#xA;around -110dB,&#xA;then find the maximum frequency&#xA;in the spectrum.&#xA;accept some command line options:&#xA;--ss n:&#xA;pass as "-ss n" to ffmpeg.&#xA;--to n:&#xA;pass as "-to n" to ffmpeg.&#xA;both -ss and -to args&#xA;must come before the -i arg&#xA;for ffmpeg input seeking.&#xA;print all frequencies in KHz.&#xA;add a shebang line before the script,&#xA;spaced by an empty line.&#xA;do not recode the audio with ffmpeg.&#xA;use ffprobe to get the input samplerate,&#xA;usually 48KHz or 44.1KHz.&#xA;create a python class,&#xA;so we dont have to pass all parameters to functions.&#xA;add a command line option to select the audio track id, by default zero.&#xA;"""&#xA;&#xA;#!/usr/bin/env python3&#xA;&#xA;import argparse&#xA;import numpy as np&#xA;import subprocess&#xA;import sys&#xA;from tempfile import NamedTemporaryFile&#xA;&#xA;&#xA;class AudioAnalyzer:&#xA;    def __init__(self, input_file, audio_track=0, start_time=None, end_time=None):&#xA;        self.input_file = input_file&#xA;        self.audio_track = audio_track&#xA;        self.start_time = start_time&#xA;        self.end_time = end_time&#xA;        self.sample_rate = self._get_sample_rate()&#xA;        self.global_max_freq = 0&#xA;        self.global_max_time = 0&#xA;&#xA;    def _get_sample_rate(self):&#xA;        cmd = [&#xA;            &#x27;ffprobe&#x27;,&#xA;            &#x27;-v&#x27;, &#x27;error&#x27;,&#xA;            &#x27;-select_streams&#x27;, f&#x27;a:{self.audio_track}&#x27;,&#xA;            &#x27;-show_entries&#x27;, &#x27;stream=sample_rate&#x27;,&#xA;            &#x27;-of&#x27;, &#x27;default=noprint_wrappers=1:nokey=1&#x27;,&#xA;            self.input_file&#xA;        ]&#xA;        result = subprocess.run(cmd, capture_output=True, text=True)&#xA;        return float(result.stdout.strip())&#xA;&#xA;    def _get_ffmpeg_command(self):&#xA;        cmd = [&#xA;            &#x27;ffmpeg&#x27;,&#xA;            &#x27;-hide_banner&#x27;,&#xA;            &#x27;-loglevel&#x27;, &#x27;error&#x27;,&#xA;        ]&#xA;        &#xA;        if self.start_time is not None:&#xA;            cmd.extend([&#x27;-ss&#x27;, str(self.start_time)])&#xA;        if self.end_time is not None:&#xA;            cmd.extend([&#x27;-to&#x27;, str(self.end_time)])&#xA;            &#xA;        cmd.extend([&#xA;            &#x27;-i&#x27;, self.input_file,&#xA;            &#x27;-map&#x27;, f&#x27;0:a:{self.audio_track}&#x27;,&#xA;            &#x27;-ac&#x27;, &#x27;1&#x27;,  # convert to mono&#xA;            &#x27;-f&#x27;, &#x27;f32le&#x27;,  # 32-bit float PCM&#xA;            &#x27;-&#x27;&#xA;        ])&#xA;        &#xA;        return cmd&#xA;&#xA;    def analyze(self, chunk_size=10):&#xA;        ffmpeg_cmd = self._get_ffmpeg_command()&#xA;        &#xA;        with subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE) as process:&#xA;            chunk_samples = int(chunk_size * self.sample_rate)&#xA;            bytes_per_sample = 4  # 32-bit float&#xA;            chunk_bytes = chunk_samples * bytes_per_sample&#xA;            &#xA;            current_time = self.start_time if self.start_time is not None else 0&#xA;            &#xA;            while True:&#xA;                raw_data = process.stdout.read(chunk_bytes)&#xA;                if not raw_data:&#xA;                    break&#xA;                &#xA;                samples = np.frombuffer(raw_data, dtype=np.float32)&#xA;                if len(samples) == 0:&#xA;                    continue&#xA;                &#xA;                local_max_freq = self._analyze_chunk(samples)&#xA;                &#xA;                print(f"t={current_time:.1f}sec f={local_max_freq:.1f}KHz")&#xA;                &#xA;                if local_max_freq > self.global_max_freq:&#xA;                    self.global_max_freq = local_max_freq&#xA;                    self.global_max_time = current_time&#xA;                &#xA;                current_time &#x2B;= chunk_size&#xA;&#xA;    def _analyze_chunk(self, samples):&#xA;        # Apply Hanning window&#xA;        window = np.hanning(len(samples))&#xA;        windowed_samples = samples * window&#xA;        &#xA;        # Compute FFT&#xA;        fft = np.fft.rfft(windowed_samples)&#xA;        magnitudes = np.abs(fft)&#xA;        &#xA;        # Convert to dB&#xA;        eps = 1e-10  # avoid log(0)&#xA;        magnitudes_db = 20 * np.log10(magnitudes &#x2B; eps)&#xA;        &#xA;        # Frequency bins&#xA;        freqs = np.fft.rfftfreq(len(samples), 1.0 / self.sample_rate) / 1000  # in KHz&#xA;        &#xA;        # Remove noise floor (-110dB)&#xA;        threshold = -110&#xA;        valid_indices = magnitudes_db > threshold&#xA;        valid_freqs = freqs[valid_indices]&#xA;        valid_magnitudes = magnitudes_db[valid_indices]&#xA;        &#xA;        if len(valid_freqs) == 0:&#xA;            return 0&#xA;        &#xA;        # Find frequency with maximum magnitude&#xA;        max_idx = np.argmax(valid_magnitudes)&#xA;        max_freq = valid_freqs[max_idx]&#xA;        &#xA;        return max_freq&#xA;&#xA;&#xA;def main():&#xA;    parser = argparse.ArgumentParser(description=&#x27;Detect maximum frequency in audio file&#x27;)&#xA;    parser.add_argument(&#x27;input_file&#x27;, help=&#x27;Input audio file (m4a)&#x27;)&#xA;    parser.add_argument(&#x27;--ss&#x27;, type=float, help=&#x27;Start time in seconds&#x27;)&#xA;    parser.add_argument(&#x27;--to&#x27;, type=float, help=&#x27;End time in seconds&#x27;)&#xA;    parser.add_argument(&#x27;--track&#x27;, type=int, default=0, help=&#x27;Audio track ID (default: 0)&#x27;)&#xA;    args = parser.parse_args()&#xA;&#xA;    analyzer = AudioAnalyzer(&#xA;        input_file=args.input_file,&#xA;        audio_track=args.track,&#xA;        start_time=args.ss,&#xA;        end_time=args.to&#xA;    )&#xA;    &#xA;    print(f"Analyzing audio file: {args.input_file}")&#xA;    print(f"Sample rate: {analyzer.sample_rate/1000:.1f} KHz")&#xA;    print(f"Audio track: {args.track}")&#xA;    if args.ss is not None:&#xA;        print(f"Start time: {args.ss} sec")&#xA;    if args.to is not None:&#xA;        print(f"End time: {args.to} sec")&#xA;    print("---")&#xA;    &#xA;    analyzer.analyze()&#xA;    &#xA;    print("---")&#xA;    print(f"Global maximum: t={analyzer.global_max_time:.1f}sec f={analyzer.global_max_freq:.1f}KHz")&#xA;    &#xA;    if analyzer.global_max_freq > 15:&#xA;        print("Quality: Fullband (high quality)")&#xA;    elif analyzer.global_max_freq > 5:&#xA;        print("Quality: Wideband (medium quality)")&#xA;    else:&#xA;        print("Quality: Narrowband (low quality)")&#xA;&#xA;&#xA;if __name__ == &#x27;__main__&#x27;:&#xA;    main()&#xA;

    &#xA;

    Similar question :&#xA;How to find the max frequency at a certain db in a fft signal

    &#xA;


    &#xA;

    edited by kesh

    &#xA;

    Here is an example psd indicating the fullband quality with a psd dropoff around 20 kHz.

    &#xA;

    psd plot

    &#xA;

  • Building FFMPEG on UBUNTU facing issue while compiling common.mak file

    9 juin 2016, par sumit singh

    I am compiling the ffmpeg library i am facing some issues while compiling this.

    I follow the steps of compilation form here.But i am failed to compile.
    The issues are as below.

    WARNING: /home/sumit/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-pkg-config not found, library detection may fail.
    libavcodec/bsf_list.c is unchanged
    libavformat/protocol_list.c is unchanged
    common.mak:26: *** unterminated call to function `foreach': missing `)'.  Stop.
    common.mak:26: *** unterminated call to function `foreach': missing `)'.  Stop.
    common.mak:26: *** unterminated call to function `foreach': missing `)'.  Stop.
    sumit@sumit-H81M-S:~/android-ndk-r10e/sources/ffmpeg$

    here is my build_android.sh file-

    #!/bin/bash

    NDK=$HOME/android-ndk-r10e

    SYSROOT=$NDK/platforms/android-19/arch-arm/

    TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86

    function build_one

    {
    ./configure --prefix=$PREFIX --enable-shared --disable-static --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-avdevice --disable-doc --disable-symver --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- --target-os=linux --arch=arm --enable-cross-compile --sysroot=$SYSROOT --extra-cflags="-Os -fpic $ADDI_CFLAGS" --extra-ldflags="$ADDI_LDFLAGS"
    $ADDITIONAL_CONFIGURE_FLAG
    make clean
    make
    make install
    }

    CPU=arm

    PREFIX=$(pwd)/android/$CPU

    ADDI_CFLAGS="-marm"

    build_one

    common.mak-

    #
    # common bits used by all libraries
    #

    # first so "all" becomes default target
    all: all-yes

    DEFAULT_YASMD=.dbg

    ifeq ($(DBG),1)
    YASMD=$(DEFAULT_YASMD)
    else
    YASMD=
    endif

    ifndef SUBDIR

    ifndef V
    Q      = @
    ECHO   = printf "$(1)\t%s\n" $(2)
    BRIEF  = CC CXX OBJCC HOSTCC HOSTLD AS YASM AR LD STRIP CP WINDRES
    SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM

    MSG    = $@
    M      = @$(call ECHO,$(TAG),$@);
    $(foreach VAR,$(BRIEF), \
       $(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
    $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
    $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
    endif

    ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample

    # NASM requires -I path terminated with /
    IFLAGS     := -I. -I$(SRC_LINK)/
    CPPFLAGS   := $(IFLAGS) $(CPPFLAGS)
    CFLAGS     += $(ECFLAGS)
    CCFLAGS     = $(CPPFLAGS) $(CFLAGS)
    OBJCFLAGS  += $(EOBJCFLAGS)
    OBJCCFLAGS  = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS)
    ASFLAGS    := $(CPPFLAGS) $(ASFLAGS)
    CXXFLAGS   += $(CPPFLAGS) $(CFLAGS)
    YASMFLAGS  += $(IFLAGS:%=%/) -Pconfig.asm

    HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
    LDFLAGS    := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)

    define COMPILE
          $(call $(1)DEP,$(1))
          $($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$&lt;)
    endef

    COMPILE_C = $(call COMPILE,CC)
    COMPILE_CXX = $(call COMPILE,CXX)
    COMPILE_S = $(call COMPILE,AS)
    COMPILE_M = $(call COMPILE,OBJCC)
    COMPILE_HOSTC = $(call COMPILE,HOSTCC)

    %.o: %.c
       $(COMPILE_C)

    %.o: %.cpp
       $(COMPILE_CXX)

    %.o: %.m
       $(COMPILE_M)

    %.s: %.c
       $(CC) $(CCFLAGS) -S -o $@ $&lt;

    %.o: %.S
       $(COMPILE_S)

    %_host.o: %.c
       $(COMPILE_HOSTC)

    %.o: %.rc
       $(WINDRES) $(IFLAGS) --preprocessor "$(DEPWINDRES) -E -xc-header -DRC_INVOKED $(CC_DEPFLAGS)" -o $@ $&lt;

    %.i: %.c
       $(CC) $(CCFLAGS) $(CC_E) $&lt;

    %.h.c:
       $(Q)echo '#include "$*.h"' >$@

    %.ver: %.v
       $(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ | sed -e 's/:/:\
    /' -e 's/; /;\
    /g' > $@

    %.c %.h: TAG = GEN

    # Dummy rule to stop make trying to rebuild removed or renamed headers
    %.h:
       @:

    # Disable suffix rules.  Most of the builtin rules are suffix rules,
    # so this saves some time on slow systems.
    .SUFFIXES:

    # Do not delete intermediate files from chains of implicit rules
    $(OBJS):
    endif

    include $(SRC_PATH)/arch.mak

    OBJS      += $(OBJS-yes)
    SLIBOBJS  += $(SLIBOBJS-yes)
    FFLIBS    := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS)
    TESTPROGS += $(TESTPROGS-yes)

    LDLIBS       = $(FFLIBS:%=%$(BUILDSUF))
    FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS)

    OBJS      := $(sort $(OBJS:%=$(SUBDIR)%))
    SLIBOBJS  := $(sort $(SLIBOBJS:%=$(SUBDIR)%))
    TESTOBJS  := $(TESTOBJS:%=$(SUBDIR)%) $(TESTPROGS:%=$(SUBDIR)%-test.o)
    TESTPROGS := $(TESTPROGS:%=$(SUBDIR)%-test$(EXESUF))
    HOSTOBJS  := $(HOSTPROGS:%=$(SUBDIR)%.o)
    HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
    TOOLS     += $(TOOLS-yes)
    TOOLOBJS  := $(TOOLS:%=tools/%.o)
    TOOLS     := $(TOOLS:%=tools/%$(EXESUF))
    HEADERS   += $(HEADERS-yes)

    PATH_LIBNAME = $(foreach NAME,$(1),lib$(NAME)/$($(2)LIBNAME))
    DEP_LIBS := $(foreach lib,$(FFLIBS),$(call PATH_LIBNAME,$(lib),$(CONFIG_SHARED:yes=S)))
    STATIC_DEP_LIBS := $(foreach lib,$(FFLIBS),$(call PATH_LIBNAME,$(lib)))

    SRC_DIR    := $(SRC_PATH)/lib$(NAME)
    ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)/$(ARCH)/*.h))
    SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
    SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
    HOBJS        = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
    checkheaders: $(HOBJS)
    .SECONDARY:   $(HOBJS:.o=.c)

    alltools: $(TOOLS)

    $(HOSTOBJS): %.o: %.c
       $(COMPILE_HOSTC)

    $(HOSTPROGS): %$(HOSTEXESUF): %.o
       $(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTLIBS)

    $(OBJS):     | $(sort $(dir $(OBJS)))
    $(HOBJS):    | $(sort $(dir $(HOBJS)))
    $(HOSTOBJS): | $(sort $(dir $(HOSTOBJS)))
    $(SLIBOBJS): | $(sort $(dir $(SLIBOBJS)))
    $(TESTOBJS): | $(sort $(dir $(TESTOBJS)))
    $(TOOLOBJS): | tools

    OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS))

    CLEANSUFFIXES     = *.d *.o *~ *.h.c *.map *.ver *.ver-sol2 *.ho *.gcno *.gcda *$(DEFAULT_YASMD).asm
    DISTCLEANSUFFIXES = *.pc
    LIBSUFFIXES       = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a

    define RULES
    clean::
       $(RM) $(HOSTPROGS)
       $(RM) $(TOOLS)
    endef

    $(eval $(RULES))

    -include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_YASMD).d)