Recherche avancée

Médias (91)

Autres articles (39)

  • Submit bugs and patches

    13 avril 2011

    Unfortunately a software is never perfect.
    If you think you have found a bug, report it using our ticket system. Please to help us to fix it by providing the following information : the browser you are using, including the exact version as precise an explanation as possible of the problem if possible, the steps taken resulting in the problem a link to the site / page in question
    If you think you have solved the bug, fill in a ticket and attach to it a corrective patch.
    You may also (...)

  • (Dés)Activation de fonctionnalités (plugins)

    18 février 2011, par

    Pour gérer l’ajout et la suppression de fonctionnalités supplémentaires (ou plugins), MediaSPIP utilise à partir de la version 0.2 SVP.
    SVP permet l’activation facile de plugins depuis l’espace de configuration de MediaSPIP.
    Pour y accéder, il suffit de se rendre dans l’espace de configuration puis de se rendre sur la page "Gestion des plugins".
    MediaSPIP est fourni par défaut avec l’ensemble des plugins dits "compatibles", ils ont été testés et intégrés afin de fonctionner parfaitement avec chaque (...)

  • Le plugin : Podcasts.

    14 juillet 2010, par

    Le problème du podcasting est à nouveau un problème révélateur de la normalisation des transports de données sur Internet.
    Deux formats intéressants existent : Celui développé par Apple, très axé sur l’utilisation d’iTunes dont la SPEC est ici ; Le format "Media RSS Module" qui est plus "libre" notamment soutenu par Yahoo et le logiciel Miro ;
    Types de fichiers supportés dans les flux
    Le format d’Apple n’autorise que les formats suivants dans ses flux : .mp3 audio/mpeg .m4a audio/x-m4a .mp4 (...)

Sur d’autres sites (6039)

  • How to fix the ffmpeg python issue "Error applying option 'original_size' to filter 'ass' : Invalid argument" ?

    16 février, par Gauthier Buttez

    ENVIRONMENT :

    


    Python 3.10

    


    Windows 11

    


    ffmpeg-python==0.2.0

    


    CONTEXT :

    


    I am trying to add hardcoded subtitles on a video with ffmpeg and Pyton.

    


    PROBLEM :

    


    ffmpeg is not able to find the path of my ass subtitle file. So I tried different ways with different methods. I asked different AI to try to find a solution. Impossible ! It is such a crazy issue that I tested the code from a "test" folder located on the root "C :" from the command line wid nows. No AI was able to fixed this issue. I tried chatGPT, deepseek, claude.ai. They proposed different solutions which were not working.

    


    THE CODE :

    


    import os
import ffmpeg
import subprocess

def add_subtitles_with_ass(video_path, ass_path, output_path):

    video_path = os.path.abspath(video_path)
    ass_path = os.path.abspath(ass_path)
    output_path = os.path.abspath(output_path)

    print(f"🚀 Add susbtitiles with ASS : {ass_path}")
    ass_path_escaped = rf'"{ass_path}"'

    try:
        ffmpeg.input(video_path).output(output_path, vf=f"ass='{ass_path_escaped}'").run(overwrite_output=True)
        print(f"✅ Subtitles added with success : {output_path}")
    except Exception as e:
        print(f"❌ ERROR when adding subtitles : {e}")


def add_subtitles_with_ass_with_subprocess(video_path, ass_path, output_path):
    video_path = os.path.abspath(video_path)
    ass_path = os.path.abspath(ass_path)
    output_path = os.path.abspath(output_path)

    print(f"🚀 Add subtitles with ASS : {ass_path}")

    try:
        command = [
            'ffmpeg',
            '-i', video_path,
            '-vf', f"ass='{ass_path}'",
            '-c:a', 'copy',
            output_path,
            '-y'  # Overwrite output file without asking
        ]

        subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        print(f"✅ Subtitles added with success : {output_path}")
    except subprocess.CalledProcessError as e:
        print(f"❌ ERROR when adding subtitles : {e.stderr.decode('utf-8')}")


print(f"Test 1 -----------------------------------------------------------------------")
ass_path="G:\Mi unidad\Python\Scripts\shorts_videos\10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path="G:\Mi unidad\Python\Scripts\shorts_videos\10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path="G:\Mi unidad\Python\Scripts\shorts_videos\10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path, ass_path, output_path)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 2 -----------------------------------------------------------------------")
ass_path2="G:\\Mi unidad\\Python\\Scripts\\shorts_videos\\10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path2="G:\\Mi unidad\\Python\\Scripts\\shorts_videos\\10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path2="G:\\Mi unidad\\Python\\Scripts\\shorts_videos\\10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path2, ass_path2, output_path2)

print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 3 -----------------------------------------------------------------------")
ass_path3="G:/\Mi unidad/\Python/\Scripts/\shorts_videos/\10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path3="G:/\Mi unidad/\Python/\Scripts/\shorts_videos/\10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path3="G:/\Mi unidad/\Python/\Scripts/\shorts_videos/\10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path3, ass_path3, output_path3)

print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 4 -----------------------------------------------------------------------")
ass_path4="G:/\\Mi unidad/\\Python/\\Scripts/\\shorts_videos/\\10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path4="G:/\\Mi unidad/\\Python/\\Scripts/\\shorts_videos/\\10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path4="G:/\\Mi unidad/\\Python/\\Scripts/\\shorts_videos/\\10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path4, ass_path4, output_path4)




print(f"Test 1 with subprocess -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path, ass_path, output_path)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 2 with subprocess -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path2, ass_path2, output_path2)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 3 with subprocess -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path3, ass_path3, output_path3)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 4 with subprocess -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path4, ass_path4, output_path4)
print(50*"*")
print(50*"*")
print(50*"*")

#======================= IT DIDN'T WORK, SO LET'S DO WITH RELATIVE PATH ===================================


print(f"Test 1 with relative path -----------------------------------------------------------------------")
ass_path_relative="10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path_relative="10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path_relative="10000views_and_higher\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path_relative, ass_path_relative, output_path_relative)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 2  with relative path -----------------------------------------------------------------------")
ass_path2_relative="10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path2_relative="10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path2_relative="10000views_and_higher\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path2_relative, ass_path2_relative, output_path2_relative)

print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 3  with relative path -----------------------------------------------------------------------")
ass_path3_relative="10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path3_relative="10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path3_relative="10000views_and_higher/\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path3_relative, ass_path3_relative, output_path3_relative)

print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 4  with relative path -----------------------------------------------------------------------")
ass_path4_relative="10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.ass"
video_path4_relative="10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo.mp4"
output_path4_relative="10000views_and_higher/\\Li2zY7XcOf0_Matthew_Hussey_flip_h_BW_with_logo_EN.mp4"
add_subtitles_with_ass(video_path4_relative, ass_path4_relative, output_path4_relative)




print(f"Test 1 with subprocess  with relative path -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path, ass_path, output_path)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 2 with subprocess  with relative path -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path2_relative, ass_path2_relative, output_path2_relative)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 3 with subprocess  with relative path -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path3_relative, ass_path3_relative, output_path3_relative)
print(50*"*")
print(50*"*")
print(50*"*")

print(f"Test 4 with subprocess  with relative path -----------------------------------------------------------------------")
add_subtitles_with_ass_with_subprocess(video_path4_relative, ass_path4_relative, output_path4_relative)
print(50*"*")
print(50*"*")
print(50*"*")


    


    THE OUTPUT :

    


    The output was too large to post it here. I uploaded it on my github :

    


    https://github.com/gauthierbuttez/public/blob/master/output_ffmpeg.log

    


    I also zipped and uploaded all the files to make reproducing the issue on your computer easy :

    


    https://github.com/gauthierbuttez/public/blob/master/test.zip

    


    Is there any kind super Python Master in the place ?

    


  • Merged Video Contains Inverted Clips After First Video Ends

    3 février, par Nikunj Agrawal

    I am working on a Flutter application that merges multiple videos using ffmpeg_kit_flutter . However, after merging, I notice that the second video (and any subsequent ones) appear inverted or rotated in the final output.

    


    Issue Details :

    


      

    1. The first video appears normal.
    2. 


    3. The videos can be recorded using both front and back cameras.
    4. 


    5. The second (and later) videos are flipped or rotated upside down.
    6. 


    7. This happens after merging using ffmpeg_kit_flutter.
    8. 


    


    Question :
How can I correctly merge multiple videos in Flutter without rotation issues ? Is there a way to normalize video orientation before merging using ffmpeg_kit_flutter ?

    


    Any help would be appreciated ! 🚀

    


    Code :

    


    import &#x27;dart:io&#x27;;&#xA;import &#x27;dart:math&#x27;;&#xA;&#xA;import &#x27;package:camera/camera.dart&#x27;;&#xA;import &#x27;package:ffmpeg_kit_flutter/ffmpeg_kit.dart&#x27;;&#xA;import &#x27;package:ffmpeg_kit_flutter/return_code.dart&#x27;;&#xA;import &#x27;package:flutter/material.dart&#x27;;&#xA;import &#x27;package:path_provider/path_provider.dart&#x27;;&#xA;import &#x27;package:permission_handler/permission_handler.dart&#x27;;&#xA;import &#x27;package:record/record.dart&#x27;;&#xA;import &#x27;package:videotest/video_player.dart&#x27;;&#xA;&#xA;class MergeVideoRecording extends StatefulWidget {&#xA;  const MergeVideoRecording({super.key});&#xA;&#xA;  @override&#xA;  State<mergevideorecording> createState() => _MergeVideoRecordingState();&#xA;}&#xA;&#xA;class _MergeVideoRecordingState extends State<mergevideorecording> {&#xA;  CameraController? _cameraController;&#xA;  final AudioRecorder _audioRecorder = AudioRecorder();&#xA;&#xA;  bool _isRecording = false;&#xA;  String? _videoPath;&#xA;  String? _audioPath;&#xA;  List<cameradescription> _cameras = [];&#xA;  int _currentCameraIndex = 0;&#xA;  final List<string> _recordedVideos = [];&#xA;&#xA;  @override&#xA;  Widget build(BuildContext context) {&#xA;    return Scaffold(&#xA;      body: Column(&#xA;        mainAxisAlignment: MainAxisAlignment.center,&#xA;        children: [&#xA;          _cameraController != null &amp;&amp; _cameraController!.value.isInitialized&#xA;              ? SizedBox(&#xA;                  width: MediaQuery.of(context).size.width * 0.4,&#xA;                  height: MediaQuery.of(context).size.height * 0.3,&#xA;                  child: Stack(&#xA;                    children: [&#xA;                      ClipRRect(&#xA;                        borderRadius: BorderRadius.circular(16),&#xA;                        child: SizedBox(&#xA;                          width: MediaQuery.of(context).size.width * 0.4,&#xA;                          height: MediaQuery.of(context).size.height * 0.3,&#xA;                          child: Transform(&#xA;                            alignment: Alignment.center,&#xA;                            transform:&#xA;                                _cameras[_currentCameraIndex].lensDirection ==&#xA;                                        CameraLensDirection.front&#xA;                                    ? Matrix4.rotationY(pi)&#xA;                                    : Matrix4.identity(),&#xA;                            child: CameraPreview(_cameraController!),&#xA;                          ),&#xA;                        ),&#xA;                      ),&#xA;                      Align(&#xA;                        alignment: Alignment.topRight,&#xA;                        child: InkWell(&#xA;                          onTap: _switchCamera,&#xA;                          child: const Padding(&#xA;                            padding: EdgeInsets.all(8.0),&#xA;                            child: CircleAvatar(&#xA;                              radius: 18,&#xA;                              backgroundColor: Colors.white,&#xA;                              child: Icon(&#xA;                                Icons.flip_camera_android,&#xA;                                color: Colors.black,&#xA;                              ),&#xA;                            ),&#xA;                          ),&#xA;                        ),&#xA;                      ),&#xA;                    ],&#xA;                  ),&#xA;                )&#xA;              : const CircularProgressIndicator(),&#xA;          const SizedBox(height: 16),&#xA;          Row(&#xA;            mainAxisAlignment: MainAxisAlignment.center,&#xA;            children: [&#xA;              FloatingActionButton(&#xA;                heroTag: &#x27;record_button&#x27;,&#xA;                onPressed: _toggleRecording,&#xA;                child: Icon(&#xA;                  _isRecording ? Icons.stop : Icons.video_camera_back,&#xA;                ),&#xA;              ),&#xA;              const SizedBox(&#xA;                width: 50,&#xA;              ),&#xA;              FloatingActionButton(&#xA;                heroTag: &#x27;merge_button&#x27;,&#xA;                onPressed: _mergeVideos,&#xA;                child: const Icon(&#xA;                  Icons.merge,&#xA;                ),&#xA;              ),&#xA;            ],&#xA;          ),&#xA;          if (!_isRecording)&#xA;            ListView.builder(&#xA;              shrinkWrap: true,&#xA;              itemCount: _recordedVideos.length,&#xA;              itemBuilder: (context, index) => InkWell(&#xA;                onTap: () {&#xA;                  Navigator.push(&#xA;                    context,&#xA;                    MaterialPageRoute(&#xA;                      builder: (context) => VideoPlayerScreen(&#xA;                        videoPath: _recordedVideos[index],&#xA;                      ),&#xA;                    ),&#xA;                  );&#xA;                },&#xA;                child: ListTile(&#xA;                  title: Text(&#x27;Video ${index &#x2B; 1}&#x27;),&#xA;                  subtitle: Text(&#x27;Path ${_recordedVideos[index]}&#x27;),&#xA;                  trailing: const Icon(Icons.play_arrow),&#xA;                ),&#xA;              ),&#xA;            ),&#xA;        ],&#xA;      ),&#xA;    );&#xA;  }&#xA;&#xA;  @override&#xA;  void dispose() {&#xA;    _cameraController?.dispose();&#xA;    _audioRecorder.dispose();&#xA;    super.dispose();&#xA;  }&#xA;&#xA;  @override&#xA;  void initState() {&#xA;    super.initState();&#xA;    _initializeDevices();&#xA;  }&#xA;&#xA;  Future<void> _initializeCameraController(CameraDescription camera) async {&#xA;    _cameraController = CameraController(&#xA;      camera,&#xA;      ResolutionPreset.high,&#xA;      enableAudio: true,&#xA;      imageFormatGroup: ImageFormatGroup.yuv420, // Add this line&#xA;    );&#xA;&#xA;    await _cameraController!.initialize();&#xA;    await _cameraController!.setExposureMode(ExposureMode.auto);&#xA;    await _cameraController!.setFocusMode(FocusMode.auto);&#xA;    setState(() {});&#xA;  }&#xA;&#xA;  Future<void> _initializeDevices() async {&#xA;    final cameraStatus = await Permission.camera.request();&#xA;    final micStatus = await Permission.microphone.request();&#xA;&#xA;    if (!cameraStatus.isGranted || !micStatus.isGranted) {&#xA;      _showError(&#x27;Camera and microphone permissions required&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    _cameras = await availableCameras();&#xA;    if (_cameras.isNotEmpty) {&#xA;      final frontCameraIndex = _cameras.indexWhere(&#xA;          (camera) => camera.lensDirection == CameraLensDirection.front);&#xA;      _currentCameraIndex = frontCameraIndex != -1 ? frontCameraIndex : 0;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;    }&#xA;  }&#xA;&#xA;  // Merge video&#xA;  Future<void> _mergeVideos() async {&#xA;    if (_recordedVideos.isEmpty) {&#xA;      _showError(&#x27;No videos to merge&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    try {&#xA;      // Debug logging&#xA;      print(&#x27;Starting merge process&#x27;);&#xA;      print(&#x27;Number of videos to merge: ${_recordedVideos.length}&#x27;);&#xA;      for (var i = 0; i &lt; _recordedVideos.length; i&#x2B;&#x2B;) {&#xA;        final file = File(_recordedVideos[i]);&#xA;        final exists = await file.exists();&#xA;        final size = exists ? await file.length() : 0;&#xA;        print(&#x27;Video $i: ${_recordedVideos[i]}&#x27;);&#xA;        print(&#x27;Exists: $exists, Size: $size bytes&#x27;);&#xA;      }&#xA;&#xA;      final Directory appDir = await getApplicationDocumentsDirectory();&#xA;      final String outputPath =&#xA;          &#x27;${appDir.path}/merged_${DateTime.now().millisecondsSinceEpoch}.mp4&#x27;;&#xA;      final String listFilePath = &#x27;${appDir.path}/list.txt&#x27;;&#xA;&#xA;      print(&#x27;Output path: $outputPath&#x27;);&#xA;      print(&#x27;List file path: $listFilePath&#x27;);&#xA;&#xA;      // Create and verify list file&#xA;      final listFile = File(listFilePath);&#xA;      final fileContent = _recordedVideos&#xA;          .map((path) => "file &#x27;${path.replaceAll("&#x27;", "&#x27;\\&#x27;&#x27;")}&#x27;")&#xA;          .join(&#x27;\n&#x27;);&#xA;      await listFile.writeAsString(fileContent);&#xA;&#xA;      print(&#x27;List file content:&#x27;);&#xA;      print(await listFile.readAsString());&#xA;&#xA;      // Simpler FFmpeg command for testing&#xA;      final command = &#x27;&#x27;&#x27;&#xA;      -f concat&#xA;      -safe 0&#xA;      -i "$listFilePath"&#xA;      -c copy&#xA;      -y&#xA;      "$outputPath"&#xA;    &#x27;&#x27;&#x27;&#xA;          .trim()&#xA;          .replaceAll(&#x27;\n&#x27;, &#x27; &#x27;);&#xA;&#xA;      print(&#x27;Executing FFmpeg command: $command&#x27;);&#xA;&#xA;      final session = await FFmpegKit.execute(command);&#xA;      final returnCode = await session.getReturnCode();&#xA;      final logs = await session.getAllLogsAsString();&#xA;      final failStackTrace = await session.getFailStackTrace();&#xA;&#xA;      print(&#x27;FFmpeg return code: ${returnCode?.getValue() ?? "null"}&#x27;);&#xA;      print(&#x27;FFmpeg logs: $logs&#x27;);&#xA;      if (failStackTrace != null) {&#xA;        print(&#x27;FFmpeg fail stack trace: $failStackTrace&#x27;);&#xA;      }&#xA;&#xA;      if (ReturnCode.isSuccess(returnCode)) {&#xA;        final outputFile = File(outputPath);&#xA;        final outputExists = await outputFile.exists();&#xA;        final outputSize = outputExists ? await outputFile.length() : 0;&#xA;&#xA;        print(&#x27;Output file exists: $outputExists&#x27;);&#xA;        print(&#x27;Output file size: $outputSize bytes&#x27;);&#xA;&#xA;        if (outputExists &amp;&amp; outputSize > 0) {&#xA;          setState(() => _recordedVideos.add(outputPath));&#xA;          _showSuccess(&#x27;Videos merged successfully&#x27;);&#xA;        } else {&#xA;          _showError(&#x27;Merged file is empty or not created&#x27;);&#xA;        }&#xA;      } else {&#xA;        _showError(&#x27;Failed to merge videos. Check logs for details.&#x27;);&#xA;      }&#xA;&#xA;      // Clean up&#xA;      try {&#xA;        await listFile.delete();&#xA;        print(&#x27;List file cleaned up successfully&#x27;);&#xA;      } catch (e) {&#xA;        print(&#x27;Failed to delete list file: $e&#x27;);&#xA;      }&#xA;    } catch (e, s) {&#xA;      print(&#x27;Error during merge: $e&#x27;);&#xA;      print(&#x27;Stack trace: $s&#x27;);&#xA;      _showError(&#x27;Error merging videos: ${e.toString()}&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  void _showError(String message) {&#xA;    ScaffoldMessenger.of(context).showSnackBar(&#xA;      SnackBar(content: Text(message), backgroundColor: Colors.red),&#xA;    );&#xA;  }&#xA;&#xA;  void _showSuccess(String message) {&#xA;    ScaffoldMessenger.of(context).showSnackBar(&#xA;      SnackBar(content: Text(message), backgroundColor: Colors.green),&#xA;    );&#xA;  }&#xA;&#xA;  Future<void> _startAudioRecording() async {&#xA;    try {&#xA;      final Directory tempDir = await getTemporaryDirectory();&#xA;      final audioPath = &#x27;${tempDir.path}/recording.wav&#x27;;&#xA;      await _audioRecorder.start(const RecordConfig(), path: audioPath);&#xA;      setState(() => _isRecording = true);&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording start error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _startVideoRecording() async {&#xA;    try {&#xA;      await _cameraController!.startVideoRecording();&#xA;      setState(() => _isRecording = true);&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording start error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _stopAndSaveAudioRecording() async {&#xA;    _audioPath = await _audioRecorder.stop();&#xA;    if (_audioPath != null) {&#xA;      final Directory appDir = await getApplicationDocumentsDirectory();&#xA;      final timestamp = DateTime.now().millisecondsSinceEpoch;&#xA;      final String audioFileName = &#x27;audio_$timestamp.wav&#x27;;&#xA;      await File(_audioPath!).copy(&#x27;${appDir.path}/$audioFileName&#x27;);&#xA;      _showSuccess(&#x27;Saved: $audioFileName&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _stopAndSaveVideoRecording() async {&#xA;    try {&#xA;      final video = await _cameraController!.stopVideoRecording();&#xA;      _videoPath = video.path;&#xA;&#xA;      if (_videoPath != null) {&#xA;        final Directory appDir = await getApplicationDocumentsDirectory();&#xA;        final timestamp = DateTime.now().millisecondsSinceEpoch;&#xA;        final String videoFileName = &#x27;video_$timestamp.mp4&#x27;;&#xA;        final savedVideoPath = &#x27;${appDir.path}/$videoFileName&#x27;;&#xA;        await File(_videoPath!).copy(savedVideoPath);&#xA;&#xA;        setState(() {&#xA;          _recordedVideos.add(savedVideoPath);&#xA;          _isRecording = false;&#xA;        });&#xA;&#xA;        _showSuccess(&#x27;Saved: $videoFileName&#x27;);&#xA;      }&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording stop error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _switchCamera() async {&#xA;    if (_cameras.length &lt;= 1) return;&#xA;&#xA;    if (_isRecording) {&#xA;      await _stopAndSaveVideoRecording();&#xA;      _currentCameraIndex = (_currentCameraIndex &#x2B; 1) % _cameras.length;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;      await _startVideoRecording();&#xA;    } else {&#xA;      _currentCameraIndex = (_currentCameraIndex &#x2B; 1) % _cameras.length;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _toggleRecording() async {&#xA;    if (_cameraController == null) return;&#xA;&#xA;    if (_isRecording) {&#xA;      await _stopAndSaveVideoRecording();&#xA;      await _stopAndSaveAudioRecording();&#xA;    } else {&#xA;      _startVideoRecording();&#xA;      _startAudioRecording();&#xA;      setState(() => _recordedVideos.clear());&#xA;    }&#xA;  }&#xA;}&#xA;</void></void></void></void></void></void></void></void></void></string></cameradescription></mergevideorecording></mergevideorecording>

    &#xA;

  • WordPress Analytics plugin WP-Piwik reaches version 1.0.0 (and 50,000 active users)

    29 mai 2015, par André Bräkling — Plugins

    After six years of development, we are proud to announce the 1.0.0 release of our WP-Piwik WordPress plugin !

    Started as a simple plugin to show a selection of statistics within the WordPress dashboard, WP-Piwik has become a full Piwik integration plugin. The plugin automatically adds the Piwik tracking code to your WordPress sites. The plugin displays your analytics reports directly within the WordPress admin panel. WordPress networks (“multisite”), CDN URLs and the Piwik proxy script are also supported.

    According to WordPress.org the plugin is being used by more than 50,000 WordPress sites !

    This article explains how to install WP-Piwik and how to configure it to work with your Piwik instance.

    Install WP-Piwik

    You can get WP-Piwik using WordPress’ plugin management. Login to your WordPress admin dashboard and go to « Plugins » → « Add New ». Enter « WP-Piwik » into the search field at the top right, press enter and next to WP-Piwik choose « Install Now ».

    If you want to use WP-Piwik in your simple WordPress blog you can just click « Activate Plugin » and WP-Piwik will ask you to configure your Piwik connection.

    Running a WordPress network/multisite you can choose to « Network Activate » the plugin after the installation process. In this case, WP-Piwik will be a fully automated feature of your WordPress network automatically tracking your sites in the same Piwik instance in separate Websites.

    Alternatively you can download WP-Piwik manually from the WordPress website and upload all files to your `wp-content/plugins` directory.

    Configure your Piwik connection

    WP-Piwik lets you choose between three connection modes :

    • Self-hosted (HTTP API) : This is the default option for a self-hosted Piwik and should work for most configurations. You just have to know your Piwik URL, which is the URL you enter to access Piwik, and your auth token (see below). WP-Piwik will connect to Piwik using http(s)-requests.
    • Self-hosted (PHP API) : Choose this, if your self-hosted Piwik and WordPress are running on the same machine and you know the full server path to your Piwik instance. Beside the full server path, you also need to know your auth token (see below).
    • Cloud-hosted (Piwik Pro) : If you are using a cloud-hosted Piwik by Piwik Pro, you just need to know your user name and your auth token (see below).

    Setting up WP-Piwik

    To configure WP-Piwik you will need to specify your Authentication token.

    • If the site you want to track in Piwik is already configured in your Piwik, you only need to specify a token_auth for a user with `view` permission.
    • If you want WP-Piwik to create the website in Piwik (or if you use WP-Piwik in network mode which requires to be able to configure your sites), you should specify a token_auth which has Super User access (after the setting up phase is completed you can set the authentication token back to the token of a `view` user).

    To find your token_auth in Piwik, click on your user name in the right right corner of your Piwik dashboard, then click the « API » in the left menu. The API page displays your auth token in a colored box, just behind the “&token_auth=” string. The screenshot below shows the token_auth anonymous, but your real one will be an alpha numerous random string like a1ec31524a8eabc7a546d71d68b28d17.

    That’s it. After you entered your connection data and submitted the form, WP-Piwik will welcome you with some information :

    You can now start to configure WP-Piwik and enable the tracking code. Learn about any setting by clicking on the small question mark sign. If you have any problem configuring or using WP-Piwik feel free to use the WordPress support forum related to WP-Piwik.

    Translating WP-Piwik

    We invite you to join our translation community at Transifex and help to translate WP-Piwik in more languages !

    Happy WordPress Analytics !