ajout du patch ffmpeg + fix path
This commit is contained in:
parent
92bd89bdbf
commit
d0b2e52ee3
@ -0,0 +1,69 @@
|
|||||||
|
From 1b016179fc18059382f8e047552e7031855764a0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
|
||||||
|
Date: Wed, 7 Nov 2018 14:31:04 +0100
|
||||||
|
Subject: [PATCH] libavformat/ffmetadec: use dynamic allocation for line buffer
|
||||||
|
|
||||||
|
When adding thumbnails to OGG files, the line can easily go up to 100kB.
|
||||||
|
|
||||||
|
We thus try to allocate the file size or SIZE_MAX to avoid truncation.
|
||||||
|
---
|
||||||
|
libavformat/ffmetadec.c | 21 +++++++++++++++++----
|
||||||
|
1 file changed, 17 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libavformat/ffmetadec.c b/libavformat/ffmetadec.c
|
||||||
|
index 3290b3b7bc..ccbff51c03 100644
|
||||||
|
--- a/libavformat/ffmetadec.c
|
||||||
|
+++ b/libavformat/ffmetadec.c
|
||||||
|
@@ -128,16 +128,26 @@ static int read_tag(const uint8_t *line, AVDictionary **m)
|
||||||
|
static int read_header(AVFormatContext *s)
|
||||||
|
{
|
||||||
|
AVDictionary **m = &s->metadata;
|
||||||
|
- uint8_t line[1024];
|
||||||
|
+ int64_t line_size = avio_size(s->pb);
|
||||||
|
+ uint8_t *line;
|
||||||
|
+
|
||||||
|
+ if (line_size < 1 || line_size > SIZE_MAX)
|
||||||
|
+ line_size = SIZE_MAX;
|
||||||
|
+
|
||||||
|
+ line = av_malloc(line_size);
|
||||||
|
+ if (!line)
|
||||||
|
+ return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
while(!avio_feof(s->pb)) {
|
||||||
|
- get_line(s->pb, line, sizeof(line));
|
||||||
|
+ get_line(s->pb, line, line_size);
|
||||||
|
|
||||||
|
if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
|
||||||
|
AVStream *st = avformat_new_stream(s, NULL);
|
||||||
|
|
||||||
|
- if (!st)
|
||||||
|
+ if (!st) {
|
||||||
|
+ av_free(line);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
|
||||||
|
st->codecpar->codec_id = AV_CODEC_ID_FFMETADATA;
|
||||||
|
@@ -146,8 +156,10 @@ static int read_header(AVFormatContext *s)
|
||||||
|
} else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) {
|
||||||
|
AVChapter *ch = read_chapter(s);
|
||||||
|
|
||||||
|
- if (!ch)
|
||||||
|
+ if (!ch) {
|
||||||
|
+ av_free(line);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
m = &ch->metadata;
|
||||||
|
} else
|
||||||
|
@@ -160,6 +172,7 @@ static int read_header(AVFormatContext *s)
|
||||||
|
s->chapters[s->nb_chapters - 1]->time_base,
|
||||||
|
AV_TIME_BASE_Q);
|
||||||
|
|
||||||
|
+ av_free(line);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
2.19.1
|
||||||
|
|
25
ffmpeg-patch/README
Normal file
25
ffmpeg-patch/README
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Pour le traitement des podcasts, il est utile d'avoir un ffmpeg patché (du moins tant que le patch n'a pas été intégré dans la version officielle). C'est mmu_man (François Revol qui a fait le patch). Il permet d'ajouter par un script l'image de cover à nos podcasts sans que l'image soit floue. Sinon, il faut utiliser un logiciel avec un interface graphique, par exemple Easytag.
|
||||||
|
|
||||||
|
J'ai mis en ligne le tarball du FFmpeg que j'avais patché et compilé en novembre 2017 :
|
||||||
|
|
||||||
|
media.april.org/audio/radio-cause-commune/libre-a-vous/FFmpeg.tgz
|
||||||
|
|
||||||
|
Car visiblement le patch ne s'applique plus :
|
||||||
|
|
||||||
|
sudo apt install yasm
|
||||||
|
|
||||||
|
git clone https://github.com/FFmpeg/FFmpeg.git
|
||||||
|
|
||||||
|
cd FFmpeg
|
||||||
|
|
||||||
|
cd libavformat
|
||||||
|
|
||||||
|
git checkout d96ae9d5ea1f47a437fc0663b0cc26ff5d4d5d31
|
||||||
|
#pour être dans la version patchable
|
||||||
|
|
||||||
|
appliquer le patch:
|
||||||
|
patch < path/to/0001-libavformat-ffmetadec-use-dynamic-allocation-for-lin.patch
|
||||||
|
|
||||||
|
./configure
|
||||||
|
|
||||||
|
make
|
49
podcasts/README
Normal file
49
podcasts/README
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
Comment découper l'enregistrement en podcasts :
|
||||||
|
|
||||||
|
* Se positionner dans le dossier contenant l'enregistrement, les images, etc :
|
||||||
|
root@raspberrypi:~/lav-outils# ls -l ~/libreavous/
|
||||||
|
total 357004
|
||||||
|
drwxr-xr-x 19 root root 4096 janv. 7 11:47 FFmpeg
|
||||||
|
drwxr-xr-x 5 root root 4096 janv. 16 11:53 lav-outils
|
||||||
|
-rw-r--r-- 1 root root 99183 janv. 7 15:55 image-pour-etiqueter-podcast.jpg
|
||||||
|
-rw-r--r-- 1 root root 90081558 janv. 15 17:54 libre-a-vous-20190108.ogg
|
||||||
|
|
||||||
|
* Regarder le programme de l'émission et chercher les timestamp de début et de fin des différents podcast
|
||||||
|
|
||||||
|
* Décider d'un nom court, qui sera utilisé pour le fichier de podcast
|
||||||
|
|
||||||
|
* Écrire la conf json en s'inspirant de example.json (mettre à jour la date), par exemple :
|
||||||
|
|
||||||
|
{
|
||||||
|
"short_date" : "20190108",
|
||||||
|
"long_date" : "8 janvier 2019",
|
||||||
|
"ffmpeg_bin" : "./FFmpeg/ffmpeg",
|
||||||
|
"chapters" : [
|
||||||
|
{
|
||||||
|
"start_timestamp" : "0:03:09",
|
||||||
|
"end_timestamp" : "0:18:45",
|
||||||
|
"short_chapter_name" : "chronique-transcriptions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "00:18:45",
|
||||||
|
"end_timestamp" : "01:11:01",
|
||||||
|
"short_chapter_name" : "dinsic-etalab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "01:11:01",
|
||||||
|
"end_timestamp" : "01:23:38",
|
||||||
|
"short_chapter_name" : "logiciel-caisse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "01:23:38",
|
||||||
|
"end_timestamp" : "01:29:58",
|
||||||
|
"short_chapter_name" : "annonces"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
* Exécuter le script :
|
||||||
|
root@raspberrypi:~/libreavous# lav-outils/scripts/make-all-podcasts.pl --config lav-outils/config/lav-20190115.json
|
||||||
|
|
||||||
|
* Les podcasts se retrouvent dans le dossier courant
|
||||||
|
|
12
podcasts/config/example.json
Normal file
12
podcasts/config/example.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"short_date" : "AAAAMMDD",
|
||||||
|
"long_date" : "DD MMMM AAAA",
|
||||||
|
"ffmpeg_bin" : "./FFmpeg/ffmpeg",
|
||||||
|
"chapters" : [
|
||||||
|
{
|
||||||
|
"start_timestamp" : "HH:MM:SS",
|
||||||
|
"end_timestamp" : "HH:MM:SS",
|
||||||
|
"short_chapter_name" : ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
27
podcasts/config/lav-20190108.json
Normal file
27
podcasts/config/lav-20190108.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"short_date" : "20190108",
|
||||||
|
"long_date" : "8 janvier 2019",
|
||||||
|
"ffmpeg_bin" : "./FFmpeg/ffmpeg",
|
||||||
|
"chapters" : [
|
||||||
|
{
|
||||||
|
"start_timestamp" : "0:03:09",
|
||||||
|
"end_timestamp" : "0:18:45",
|
||||||
|
"short_chapter_name" : "chronique-transcriptions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "00:18:45",
|
||||||
|
"end_timestamp" : "01:11:01",
|
||||||
|
"short_chapter_name" : "dinsic-etalab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "01:11:01",
|
||||||
|
"end_timestamp" : "01:23:38",
|
||||||
|
"short_chapter_name" : "logiciel-caisse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start_timestamp" : "01:23:38",
|
||||||
|
"end_timestamp" : "01:29:58",
|
||||||
|
"short_chapter_name" : "annonces"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
12
podcasts/config/lav-20190115.json
Normal file
12
podcasts/config/lav-20190115.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"short_date" : "20190115",
|
||||||
|
"long_date" : "15 janvier 2019",
|
||||||
|
"ffmpeg_bin" : "./FFmpeg/ffmpeg",
|
||||||
|
"chapters" : [
|
||||||
|
{
|
||||||
|
"start_timestamp" : "00:16:27",
|
||||||
|
"end_timestamp" : "01:29:40",
|
||||||
|
"short_chapter_name" : "CADA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
podcasts/images/image-pour-etiqueter-podcast.jpg
Normal file
BIN
podcasts/images/image-pour-etiqueter-podcast.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
148
podcasts/scripts/make-all-podcasts.pl
Executable file
148
podcasts/scripts/make-all-podcasts.pl
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use JSON;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
my ($help,$config,$verbose,$dryrun);
|
||||||
|
my $meta_data_script = "lav-outils/podcasts/scripts/make-metadata-image-podcast.sh";
|
||||||
|
|
||||||
|
my $verbose;
|
||||||
|
GetOptions ("help" => \$help,
|
||||||
|
"config=s" => \$config,
|
||||||
|
"verbose" => \$verbose,
|
||||||
|
"dryrun" => \$dryrun);
|
||||||
|
|
||||||
|
if($help) {
|
||||||
|
usage();
|
||||||
|
} elsif( not $config ) {
|
||||||
|
print " /!\\ Missing config arg\n\n";
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub usage {
|
||||||
|
print <<EOS
|
||||||
|
Exec commands to cut and process LAV! podcast with json file containing the timestamps and sections to be cut.
|
||||||
|
Needs JSON perl library (apt install libjson-perl)
|
||||||
|
$0 --config conf_file.json
|
||||||
|
--config conf_file.json the configuration file containing stuff
|
||||||
|
--help show this message
|
||||||
|
--verbose increase verbosity
|
||||||
|
--dryrun print commands without executing them
|
||||||
|
EOS
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub read_config {
|
||||||
|
my ($filename) = @_;
|
||||||
|
|
||||||
|
my $json_text = do { #read all the file in one shot
|
||||||
|
open(my $json_fh, "<:encoding(UTF-8)", $filename)
|
||||||
|
or die("Can't open \$filename\": $!\n");
|
||||||
|
local $/;
|
||||||
|
<$json_fh>
|
||||||
|
};
|
||||||
|
|
||||||
|
my $json = JSON->new;
|
||||||
|
my $data = $json->decode($json_text);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub process {
|
||||||
|
my ($config,$verbose,$dryrun)=@_;
|
||||||
|
my $data = read_config($config);
|
||||||
|
|
||||||
|
my $short_date = $data->{short_date};
|
||||||
|
my $long_date = $data->{long_date};
|
||||||
|
my $source_name = "libre-a-vous-$short_date";
|
||||||
|
my $title = "Libre à vous ! du $long_date sur Cause Commune";
|
||||||
|
my $ffmpeg_bin = $data->{ffmpeg_bin};
|
||||||
|
for my $chapter (values @{$data->{chapters}}) {
|
||||||
|
my $start = $chapter->{start_timestamp};
|
||||||
|
my $end = $chapter->{end_timestamp};
|
||||||
|
my $short_chapter_name = $chapter->{short_chapter_name};
|
||||||
|
|
||||||
|
# cutting chapter
|
||||||
|
my $command = "$ffmpeg_bin -y -i $source_name.ogg -vn -acodec copy -ss \"$start\" -to \"$end\" $source_name-$short_chapter_name.ogg";
|
||||||
|
if($dryrun) {
|
||||||
|
print "$command\n";
|
||||||
|
} else {
|
||||||
|
my @ret = `$command`;
|
||||||
|
if($?) {
|
||||||
|
print "Error while cutting $short_chapter_name\n";
|
||||||
|
if($verbose) {
|
||||||
|
print Dumper @ret;
|
||||||
|
print Dumper $data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# putting metadata
|
||||||
|
my $url = "https://media.april.org/audio/radio-cause-commune/libre-a-vous/emissions/$short_date/$source_name-$short_chapter_name.ogg";
|
||||||
|
my $command = "$meta_data_script -s \"$source_name-$short_chapter_name.ogg\" -d \"output.ogg\" -u \"$url\" -t \"$title\" -p \"$ffmpeg_bin\"";
|
||||||
|
if($dryrun) {
|
||||||
|
print "$command\n";
|
||||||
|
} else {
|
||||||
|
my @ret = `$command`;
|
||||||
|
if($?) {
|
||||||
|
print "Error while setting metadata in $short_chapter_name\n";
|
||||||
|
if($verbose) {
|
||||||
|
print Dumper @ret;
|
||||||
|
print Dumper $data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $command = "mv output.ogg $source_name-$short_chapter_name.ogg";
|
||||||
|
if($dryrun) {
|
||||||
|
print "$command\n";
|
||||||
|
} else {
|
||||||
|
my @ret = `$command`;
|
||||||
|
if($?) {
|
||||||
|
print "Error while renaming $short_chapter_name\n";
|
||||||
|
if($verbose) {
|
||||||
|
print Dumper @ret;
|
||||||
|
print Dumper $data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# putting metadata in main podcast
|
||||||
|
my $url = "https://media.april.org/audio/radio-cause-commune/libre-a-vous/emissions/$short_date/$source_name.ogg";
|
||||||
|
my $command = "$meta_data_script -s \"$source_name.ogg\" -d \"output.ogg\" -u \"$url\" -t \"$title\" -p \"$ffmpeg_bin\"";
|
||||||
|
if($dryrun) {
|
||||||
|
print "$command\n";
|
||||||
|
} else {
|
||||||
|
my @ret = `$command`;
|
||||||
|
if($?) {
|
||||||
|
print "Error while setting metadata in $source_name\n";
|
||||||
|
if($verbose) {
|
||||||
|
print Dumper @ret;
|
||||||
|
print Dumper $data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $command = "mv output.ogg $source_name.ogg";
|
||||||
|
if($dryrun) {
|
||||||
|
print "$command\n";
|
||||||
|
} else {
|
||||||
|
my @ret = `$command`;
|
||||||
|
if($?) {
|
||||||
|
print "Error while renaming $source_name\n";
|
||||||
|
if($verbose) {
|
||||||
|
print Dumper @ret;
|
||||||
|
print Dumper $data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process($config,$verbose,$dryrun);
|
50
podcasts/scripts/make-metadata-image-podcast.sh
Executable file
50
podcasts/scripts/make-metadata-image-podcast.sh
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
usage() { echo "$0 -s source_file -d destination_file -u http://... -t \"title\" -p path/to/ffmpeg/binary"; exit 0; }
|
||||||
|
[ $# -eq 0 ] && usage
|
||||||
|
while getopts "s:d:u:t:p:h" arg; do
|
||||||
|
case $arg in
|
||||||
|
s)
|
||||||
|
source=${OPTARG}
|
||||||
|
;;
|
||||||
|
d)
|
||||||
|
destination=${OPTARG}
|
||||||
|
;;
|
||||||
|
u)
|
||||||
|
url=${OPTARG}
|
||||||
|
;;
|
||||||
|
t)
|
||||||
|
title=${OPTARG}
|
||||||
|
;;
|
||||||
|
p)
|
||||||
|
FFmpegBin=${OPTARG}
|
||||||
|
;;
|
||||||
|
h | *) # Display help.
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -f $source ]; then
|
||||||
|
echo "File $source does not exist"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "$FFmpegBin" ]; then
|
||||||
|
echo "$FFmpegBin is not executable"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
image="lav-outils/images/image-pour-etiqueter-podcast.jpg"
|
||||||
|
fichiertemp="$(command mktemp -t "tmp.XXXXXXXXXX.ogg")"
|
||||||
|
|
||||||
|
(echo -en ";FFMETADATA1\nMETADATA_BLOCK_PICTURE=";(i=${image};t=3;m="image/jpeg";eval "w=`identify-im6 "$i"|awk '{g=$3;sub("x"," h=",g);print g;d=$5;gsub(/-.*/,"",d);print " d=" d}'`"; echo -en "\x00\x00\x00\x$(printf '%02x' $t)\x00\x00\x00\x$(printf '%02x' `echo -n "$m"|wc -c`)$m\x00\x00\x00\x00$(printf '%08x' $w|sed 's/../\\x&/g')$(printf '%08x' $h|sed 's/../\\x&/g')$(printf '%08x' $d|sed 's/../\\x&/g')\x00\x00\x00\xff$(printf '%08x' `stat -c '%s' "$i"`|sed 's/../\\x&/g')";cat "$i")|base64 --wrap=0) > i.meta
|
||||||
|
|
||||||
|
${FFmpegBin} -y -i ${source} -acodec copy -map 0:0 -map_metadata -1 -metadata title="${title}" -metadata copyright="Diffusée selon les termes d’au moins une des licences suivantes : licence Art libre version 1.3 ou ultérieure http://artlibre.org/licence/lal/, licence Creative Commons By Sa version 2.0 ou ultérieure http://creativecommons.org/licenses/by-sa/2.0/fr/ et licence GNU FDL version 1.3 ou ultérieure http://www.gnu.org/licenses/fdl-1.3.html" -metadata artist="April - Cause Commune" -metadata contact="${url}" ${fichiertemp}
|
||||||
|
|
||||||
|
${FFmpegBin} -y -i ${fichiertemp} -i i.meta -acodec copy -map 0:0 -map_metadata 1 ${destination}
|
||||||
|
|
||||||
|
rm ${fichiertemp}
|
||||||
|
rm i.meta
|
Loading…
Reference in New Issue
Block a user