Recherche avancée

Médias (91)

Autres articles (112)

  • Personnaliser en ajoutant son logo, sa bannière ou son image de fond

    5 septembre 2013, par

    Certains thèmes prennent en compte trois éléments de personnalisation : l’ajout d’un logo ; l’ajout d’une bannière l’ajout d’une image de fond ;

  • Keeping control of your media in your hands

    13 avril 2011, par

    The vocabulary used on this site and around MediaSPIP in general, aims to avoid reference to Web 2.0 and the companies that profit from media-sharing.
    While using MediaSPIP, you are invited to avoid using words like "Brand", "Cloud" and "Market".
    MediaSPIP is designed to facilitate the sharing of creative media online, while allowing authors to retain complete control of their work.
    MediaSPIP aims to be accessible to as many people as possible and development is based on expanding the (...)

  • Personnaliser les catégories

    21 juin 2013, par

    Formulaire de création d’une catégorie
    Pour ceux qui connaissent bien SPIP, une catégorie peut être assimilée à une rubrique.
    Dans le cas d’un document de type catégorie, les champs proposés par défaut sont : Texte
    On peut modifier ce formulaire dans la partie :
    Administration > Configuration des masques de formulaire.
    Dans le cas d’un document de type média, les champs non affichés par défaut sont : Descriptif rapide
    Par ailleurs, c’est dans cette partie configuration qu’on peut indiquer le (...)

Sur d’autres sites (10155)

  • 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)/%,$<)
    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 $@ $<

    %.o: %.S
       $(COMPILE_S)

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

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

    %.i: %.c
       $(CC) $(CCFLAGS) $(CC_E) $<

    %.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)
  • FFMPEG Concatenating videos with same 25fps results in output file with 3.554fps

    5 juin 2024, par Kendra Broom

    I created an AWS Lambda function in node.js 18 that is using a static, ver 7 build of FFmpeg located in a lambda layer. Unfortunately it's just the ffmpeg build and doesn't include ffprobe.

    


    I have an mp4 audio file in one S3 bucket and a wav audio file in a second S3 bucket. I'm uploading the output file to a third S3 bucket.

    


    Specs on the files (please let me know if any more info is needed)

    


    Audio :
wav, 13kbps, aac (LC), 6:28 duration

    


    Video :
mp4, 1280x720 resolution, 25 frame rate, h264 codec, 3:27 duration

    


    Goal :
Create blank video to fill in the duration gaps so the full audio is covered before and after the mp4 video (using timestamps and duration). Strip the mp4 audio and use the wav audio only. Output should be an mp4 video with the wav audio playing over it and blank video for 27 seconds (based on timestamp) until mp4 video plays for 3:27, and then blank video to cover the rest of the audio until 6:28.

    


    Actual Result :
An mp4 file with 3.554 frame rate and 10:06 duration.

    


    import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { createWriteStream, createReadStream, promises as fsPromises } from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';
import { basename } from 'path';

const execAsync = promisify(exec);

const s3 = new S3Client({ region: 'us-east-1' });

async function downloadFileFromS3(bucket, key, downloadPath) {
    const getObjectParams = { Bucket: bucket, Key: key };
    const command = new GetObjectCommand(getObjectParams);
    const { Body } = await s3.send(command);
    return new Promise((resolve, reject) => {
        const fileStream = createWriteStream(downloadPath);
        Body.pipe(fileStream);
        Body.on('error', reject);
        fileStream.on('finish', resolve);
    });
}

async function uploadFileToS3(bucket, key, filePath) {
    const fileStream = createReadStream(filePath);
    const uploadParams = { Bucket: bucket, Key: key, Body: fileStream };
    try {
        await s3.send(new PutObjectCommand(uploadParams));
        console.log(`File uploaded successfully to ${bucket}/${key}`);
    } catch (err) {
        console.error("Error uploading file: ", err);
        throw new Error('Failed to upload file to S3');
    }
}

function parseDuration(durationStr) {
    const parts = durationStr.split(':');
    return parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseFloat(parts[2]);
}

export async function handler(event) {
    const videoBucket = "video-interaction-content";
    const videoKey = event.videoKey;
    const audioBucket = "audio-call-recordings";
    const audioKey = event.audioKey;
    const outputBucket = "synched-audio-video";
    const outputKey = `combined_${basename(videoKey, '.mp4')}.mp4`;

    const audioStartSeconds = new Date(event.audioStart).getTime() / 1000;
    const videoStartSeconds = new Date(event.videoStart).getTime() / 1000;
    const audioDurationSeconds = event.audioDuration / 1000;
    const timeDifference = audioStartSeconds - videoStartSeconds;

    try {
        const videoPath = `/tmp/${basename(videoKey)}`;
        const audioPath = `/tmp/${basename(audioKey)}`;
        await downloadFileFromS3(videoBucket, videoKey, videoPath);
        await downloadFileFromS3(audioBucket, audioKey, audioPath);

        //Initialize file list with video
        let filelist = [`file '${videoPath}'`];
        let totalVideoDuration = 0; // Initialize total video duration

        // Create first blank video if needed
        if (timeDifference < 0) {
            const blankVideoDuration = Math.abs(timeDifference);
            const blankVideoPath = `/tmp/blank_video.mp4`;
            await execAsync(`/opt/bin/ffmpeg -f lavfi -i color=c=black:s=1280x720:r=25 -c:v libx264 -t ${blankVideoDuration} ${blankVideoPath}`);
            //Add first blank video first in file list
            filelist.unshift(`file '${blankVideoPath}'`);
            totalVideoDuration += blankVideoDuration;
            console.log(`First blank video created with duration: ${blankVideoDuration} seconds`);
        }
        
        const videoInfo = await execAsync(`/opt/bin/ffmpeg -i ${videoPath} -f null -`);
        const videoDurationMatch = videoInfo.stderr.match(/Duration: ([\d:.]+)/);
        const videoDuration = videoDurationMatch ? parseDuration(videoDurationMatch[1]) : 0;
        totalVideoDuration += videoDuration;

        // Calculate additional blank video duration
        const additionalBlankVideoDuration = audioDurationSeconds - totalVideoDuration;
        if (additionalBlankVideoDuration > 0) {
            const additionalBlankVideoPath = `/tmp/additional_blank_video.mp4`;
            await execAsync(`/opt/bin/ffmpeg -f lavfi -i color=c=black:s=1280x720:r=25 -c:v libx264 -t ${additionalBlankVideoDuration} ${additionalBlankVideoPath}`);
            //Add to the end of the file list
            filelist.push(`file '${additionalBlankVideoPath}'`);
            console.log(`Additional blank video created with duration: ${additionalBlankVideoDuration} seconds`);
        }

        // Create and write the file list to disk
        const concatFilePath = '/tmp/filelist.txt';
        await fsPromises.writeFile('/tmp/filelist.txt', filelist.join('\n'));

        const extendedVideoPath = `/tmp/extended_${basename(videoKey)}`;
        //await execAsync(`/opt/bin/ffmpeg -f concat -safe 0 -i /tmp/filelist.txt -c copy ${extendedVideoPath}`);
        
        // Use -vsync vfr to adjust frame timing without full re-encoding
        await execAsync(`/opt/bin/ffmpeg -f concat -safe 0 -i ${concatFilePath} -c copy -vsync vfr ${extendedVideoPath}`);

        const outputPath = `/tmp/output_${basename(videoKey, '.mp4')}.mp4`;
        //await execAsync(`/opt/bin/ffmpeg -i ${extendedVideoPath} -i ${audioPath} -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest ${outputPath}`);

        await execAsync(`/opt/bin/ffmpeg -i ${extendedVideoPath} -i ${audioPath} -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest -r 25 ${outputPath}`);
        console.log('Video and audio have been merged successfully');

        await uploadFileToS3(outputBucket, outputKey, outputPath);
        console.log('File upload complete.');

        return { statusCode: 200, body: JSON.stringify('Video and audio have been merged successfully.') };
    } catch (error) {
        console.error('Error in Lambda function:', error);
        return { statusCode: 500, body: JSON.stringify('Failed to process video and audio.') };
    }
}


    


    Attempts :
I've tried re-encoding the concatenated file but the lambda function times out. I hoped that by creating blank video with a 25fps and all the other specs from the original mp4, I wouldn't have to re-encode the concatenated file. Obviously something is wrong, though. In the commented out code you can see I tried specifying 25 or not, and also tried -vsync and no -vsync. I'm new to FFmpeg so all tips are appreciated !

    


  • FFMPEG 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)/%,$<)
    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 $@ $<

    %.o: %.S
       $(COMPILE_S)

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

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

    %.i: %.c
       $(CC) $(CCFLAGS) $(CC_E) $<

    %.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)