Recherche avancée

Médias (0)

Mot : - Tags -/gis

Aucun média correspondant à vos critères n’est disponible sur le site.

Autres articles (63)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • Ajouter notes et légendes aux images

    7 février 2011, par

    Pour pouvoir ajouter notes et légendes aux images, la première étape est d’installer le plugin "Légendes".
    Une fois le plugin activé, vous pouvez le configurer dans l’espace de configuration afin de modifier les droits de création / modification et de suppression des notes. Par défaut seuls les administrateurs du site peuvent ajouter des notes aux images.
    Modification lors de l’ajout d’un média
    Lors de l’ajout d’un média de type "image" un nouveau bouton apparait au dessus de la prévisualisation (...)

  • Contribute to translation

    13 avril 2011

    You can help us to improve the language used in the software interface to make MediaSPIP more accessible and user-friendly. You can also translate the interface into any language that allows it to spread to new linguistic communities.
    To do this, we use the translation interface of SPIP where the all the language modules of MediaSPIP are available. Just subscribe to the mailing list and request further informantion on translation.
    MediaSPIP is currently available in French and English (...)

Sur d’autres sites (9333)

  • Vulkan image data to AVFrames and to video

    12 avril 2024, par W4zab1

    I am trying to encode Vulkan image data into video with MPEG4 format. For some reason the output videofile is corrupted. FFProbe shows discontinuity in timestamps, and the frames are corrupted.
First I prepare my video encoder
    
Then I get FrameEnded events from my engine where I can get the image data from the vulkan swapchain.
    
I then convert the image data from vulkan to AVFrames (RGBA to YUV420P), then I pass the frames into queue.
    
This queue is then handled in another thread, where the frames are processed, and written into video.
    
I am bit of a noob with ffmpeg, so there can be some code that does not make sense.

    


    This seems right straight forward logic, but there is probably some problems with codec params, way I am converting the imagedata to AVFrame, or something of that sort.
    
The videofile still gets created, and has some data in it (it is > 0 bytes, and longer the recording, bigger the filesize).
    
There is no errors from ffmpeg with log_level set to DEBUG.

    


    struct FrameData {&#xA;    AVFrame* frame;&#xA;    int frame_index;&#xA;};&#xA;&#xA;class EventListenerVideoCapture : public VEEventListenerGLFW {&#xA;private:&#xA;    AVFormatContext* format_ctx = nullptr;&#xA;    AVCodec* video_codec = nullptr;&#xA;    AVCodecContext* codec_context = nullptr;&#xA;    AVStream* video_stream = nullptr;&#xA;    AVDictionary* muxer_opts = nullptr;&#xA;    int frame_index = 0;&#xA;&#xA;    std::queue frame_queue;&#xA;    std::mutex queue_mtx;&#xA;    std::condition_variable queue_cv;&#xA;    std::atomic<bool> stop_processing{ false };&#xA;    std::thread video_processing_thread;&#xA;    int prepare_video_encoder()&#xA;    {&#xA;        av_log_set_level(AV_LOG_DEBUG);&#xA;        // Add video stream to format context&#xA;        avformat_alloc_output_context2(&amp;format_ctx, nullptr, nullptr, "video.mpg");&#xA;        video_stream = avformat_new_stream(format_ctx, NULL);&#xA;        video_codec = (AVCodec*)avcodec_find_encoder(AV_CODEC_ID_MPEG4);&#xA;        codec_context = avcodec_alloc_context3(video_codec);&#xA;        if (!format_ctx) { std::cerr &lt;&lt; "Error: Failed to allocate format context" &lt;&lt; std::endl; system("pause"); }&#xA;        if (!video_stream) { std::cerr &lt;&lt; "Error: Failed to create new stream" &lt;&lt; std::endl; system("pause"); }&#xA;        if (!video_codec) { std::cerr &lt;&lt; "Error: Failed to find video codec" &lt;&lt; std::endl; system("pause"); }&#xA;        if (!codec_context) { std::cerr &lt;&lt; "Error: Failed to allocate codec context" &lt;&lt; std::endl; system("pause"); }&#xA;&#xA;        if (avio_open(&amp;format_ctx->pb, "video.mpg", AVIO_FLAG_WRITE) &lt; 0) { std::cerr &lt;&lt; "Error: Failed to open file for writing!" &lt;&lt; std::endl; return -1; }&#xA;&#xA;        av_opt_set(codec_context->priv_data, "preset", "fast", 0);&#xA;&#xA;        codec_context->codec_id = AV_CODEC_ID_MPEG4;&#xA;        codec_context->codec_type = AVMEDIA_TYPE_VIDEO;&#xA;        codec_context->pix_fmt = AV_PIX_FMT_YUV420P;&#xA;        codec_context->width = getWindowPointer()->getExtent().width;&#xA;        codec_context->height = getWindowPointer()->getExtent().height;&#xA;        codec_context->bit_rate = 1000 * 1000; // Bitrate&#xA;        codec_context->time_base = { 1, 30 }; // 30 FPS&#xA;        codec_context->gop_size = 10;&#xA;&#xA;        av_dict_set(&amp;muxer_opts, "movflags", "faststart", 0);&#xA;&#xA;        //Unecessary? Since the params are copied anyways&#xA;        video_stream->time_base = codec_context->time_base;&#xA;&#xA;        //Try to open codec after changes&#xA;        //copy codec_context params to videostream&#xA;        //and write headers to format_context&#xA;        if (avcodec_open2(codec_context, video_codec, NULL) &lt; 0) { std::cerr &lt;&lt; "Error: Could not open codec!" &lt;&lt; std::endl; return -1; }&#xA;        if (avcodec_parameters_from_context(video_stream->codecpar, codec_context) &lt; 0) { std::cerr &lt;&lt; "Error: Could not copy params from context to stream!" &lt;&lt; std::endl; return -1; };&#xA;        if (avformat_write_header(format_ctx, &amp;muxer_opts) &lt; 0) { std::cerr &lt;&lt; "Error: Failed to write output file headers!" &lt;&lt; std::endl; return -1; }&#xA;        return 0;&#xA;    }&#xA;&#xA;    void processFrames() {&#xA;        while (!stop_processing) {&#xA;            FrameData* frameData = nullptr;&#xA;            {&#xA;                std::unique_lock lock(queue_mtx);&#xA;                queue_cv.wait(lock, [&amp;]() { return !frame_queue.empty() || stop_processing; });&#xA;&#xA;                if (stop_processing &amp;&amp; frame_queue.empty())&#xA;                    break;&#xA;&#xA;                frameData = frame_queue.front();&#xA;                frame_queue.pop();&#xA;            }&#xA;&#xA;            if (frameData) {&#xA;                encodeAndWriteFrame(frameData);&#xA;                AVFrame* frame = frameData->frame;&#xA;                av_frame_free(&amp;frame); // Free the processed frame&#xA;                delete frameData;&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    void encodeAndWriteFrame(FrameData* frameData) {&#xA;&#xA;        // Validation&#xA;        if (!frameData->frame) { std::cerr &lt;&lt; "Error: Frame was null! " &lt;&lt; std::endl; return; }&#xA;        if (frameData->frame->format != codec_context->pix_fmt) { std::cerr &lt;&lt; "Error: Frame format mismatch!" &lt;&lt; std::endl; return; }&#xA;        if ( av_frame_get_buffer(frameData->frame, 0) &lt; 0) { std::cerr &lt;&lt; "Error allocating frame buffer: " &lt;&lt; std::endl; return; }&#xA;        if (!codec_context) return;&#xA;&#xA;        AVPacket* pkt = av_packet_alloc();&#xA;        if (!pkt) { std::cerr &lt;&lt; "Error: Failed to allocate AVPacket" &lt;&lt; std::endl; system("pause"); }&#xA;&#xA;        int ret = avcodec_send_frame(codec_context, frameData->frame);&#xA;        if (ret &lt; 0) { &#xA;            std::cerr &lt;&lt; "Error receiving packet from codec: " &lt;&lt; ret &lt;&lt; std::endl;&#xA;            delete frameData;&#xA;            av_packet_free(&amp;pkt); return; &#xA;        }&#xA;&#xA;        while (ret >= 0) {&#xA;            ret = avcodec_receive_packet(codec_context, pkt);&#xA;&#xA;            //Error checks&#xA;            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; }&#xA;            else if (ret &lt; 0) { std::cerr &lt;&lt; "Error receiving packet from codec: " &lt;&lt; ret &lt;&lt; std::endl; av_packet_free(&amp;pkt); return; }&#xA;            if (!video_stream) { std::cerr &lt;&lt; "Error: video stream is null!" &lt;&lt; std::endl; av_packet_free(&amp;pkt); return; }&#xA;            &#xA;            int64_t frame_duration = codec_context->time_base.den / codec_context->time_base.num;&#xA;            pkt->stream_index = video_stream->index;&#xA;            pkt->duration = frame_duration;&#xA;            pkt->pts = frameData->frame_index * frame_duration;&#xA;&#xA;            int write_ret = av_interleaved_write_frame(format_ctx, pkt);&#xA;            if (write_ret &lt; 0) { std::cerr &lt;&lt; "Error: failed to write a frame! " &lt;&lt; write_ret &lt;&lt; std::endl;}&#xA;&#xA;            av_packet_unref(pkt);&#xA;        }&#xA;&#xA;        av_packet_free(&amp;pkt);&#xA;&#xA;    }&#xA;&#xA;protected:&#xA;    virtual void onFrameEnded(veEvent event) override {&#xA;        // Get the image data from vulkan&#xA;        VkExtent2D extent = getWindowPointer()->getExtent();&#xA;        uint32_t imageSize = extent.width * extent.height * 4;&#xA;        VkImage image = getEnginePointer()->getRenderer()->getSwapChainImage();&#xA;&#xA;        uint8_t *dataImage = new uint8_t[imageSize];&#xA;        &#xA;        vh::vhBufCopySwapChainImageToHost(getEnginePointer()->getRenderer()->getDevice(),&#xA;            getEnginePointer()->getRenderer()->getVmaAllocator(),&#xA;            getEnginePointer()->getRenderer()->getGraphicsQueue(),&#xA;            getEnginePointer()->getRenderer()->getCommandPool(),&#xA;            image, VK_FORMAT_R8G8B8A8_UNORM,&#xA;            VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,&#xA;            dataImage, extent.width, extent.height, imageSize);&#xA;        &#xA;        // Create AVFrame for the converted image data&#xA;        AVFrame* frame = av_frame_alloc();&#xA;        if (!frame) { std::cout &lt;&lt; "Could not allocate memory for frame!" &lt;&lt; std::endl; return; }&#xA;&#xA;        frame->format = AV_PIX_FMT_YUV420P;&#xA;        frame->width = extent.width;&#xA;        frame->height = extent.height;&#xA;        if (av_frame_get_buffer(frame, 0) &lt; 0) { std::cerr &lt;&lt; "Failed to allocate frame buffer! " &lt;&lt; std::endl; return;} ;&#xA;&#xA;        // Prepare context for converting from RGBA to YUV420P&#xA;        SwsContext* sws_ctx = sws_getContext(&#xA;            extent.width, extent.height, AV_PIX_FMT_RGBA,&#xA;            extent.width, extent.height, AV_PIX_FMT_YUV420P,&#xA;            SWS_BILINEAR, nullptr, nullptr, nullptr);&#xA;&#xA;        // Convert the vulkan image data to AVFrame&#xA;        uint8_t* src_data[1] = { dataImage };&#xA;        int src_linesize[1] = { extent.width * 4 };&#xA;        int scale_ret = sws_scale(sws_ctx, src_data, src_linesize, 0, extent.height,&#xA;                  frame->data, frame->linesize);&#xA;&#xA;        if (scale_ret &lt;= 0) { std::cerr &lt;&lt; "Failed to scale the image to frame" &lt;&lt; std::endl; return; }&#xA;&#xA;        sws_freeContext(sws_ctx);&#xA;        delete[] dataImage;&#xA;&#xA;        // Add frame to the queue&#xA;        {&#xA;            std::lock_guard lock(queue_mtx);&#xA;&#xA;            FrameData* frameData = new FrameData;&#xA;            frameData->frame = frame;&#xA;            frameData->frame_index = frame_index;&#xA;            frame_queue.push(frameData);&#xA;&#xA;            frame_index&#x2B;&#x2B;;&#xA;        }&#xA;&#xA;        // Notify processing thread&#xA;        queue_cv.notify_one();&#xA;    }&#xA;&#xA;public:&#xA;    EventListenerVideoCapture(std::string name) : VEEventListenerGLFW(name) {&#xA;        //Prepare the video encoder&#xA;        int ret = prepare_video_encoder();&#xA;        if (ret &lt; 0)&#xA;        {&#xA;            std::cerr &lt;&lt; "Failed to prepare video encoder! " &lt;&lt; std::endl;&#xA;            exit(-1);&#xA;        }&#xA;        else&#xA;        {&#xA;            // Start video processing thread&#xA;            video_processing_thread = std::thread(&amp;EventListenerVideoCapture::processFrames, this);&#xA;        }&#xA;    }&#xA;&#xA;    ~EventListenerVideoCapture() {&#xA;        // Stop video processing thread&#xA;        stop_processing = true;&#xA;        queue_cv.notify_one(); // Notify processing thread to stop&#xA;&#xA;        if (video_processing_thread.joinable()) {&#xA;            video_processing_thread.join();&#xA;        }&#xA;&#xA;        // Flush codec and close output file&#xA;        avcodec_send_frame(codec_context, nullptr);&#xA;        av_write_trailer(format_ctx);&#xA;&#xA;        av_dict_free(&amp;muxer_opts);&#xA;        avio_closep(&amp;format_ctx->pb);&#xA;        avcodec_free_context(&amp;codec_context);&#xA;        avformat_free_context(format_ctx);&#xA;    }&#xA;};&#xA;&#xA;</bool>

    &#xA;

    I have tried changing the codec params, debugging and printing the videoframe data with no success.

    &#xA;

  • FFMPEG & ytdl-core | Muxing highestaudio and highestvideo results in mp4 with incorrect time

    17 mars 2023, par Niek Peters

    I want to combine a file with only video and a file with only audio from the ytdl-core package into a mp4 and stream it in the response. I get the files using the highestvideo and highestaudio quality settings. I tried to modify a part of the ytdl-core-muxer module to change the output format to mp4, for which I also needed to add -movflags frag_keyframe&#x2B;empty_moov, to allow the output mp4 to be seekable. This all seems to work and it produces a mp4 file without errors. When I open it with the Windows Photos app however, I noticed that even though video plays normally in perfect quality, the time is completely wrong.

    &#xA;

    As you can see, the time says there are 53 million hours remaining, even though the video is 1:32 mins long

    &#xA;

    I have tried adding a fixed framerate with -r 60 and regenerating the timestamps with -fflags &#x2B;genpts, but to no avail. I have also tried encoding the video and audio formats to h264 (using libx264) and acc, but that didn't solve it either.

    &#xA;

    &#xD;&#xA;
    &#xD;&#xA;
    // create the ffmpeg process for muxing&#xA;const ffmpegProcess = cp.spawn(&#xA;  ffmpeg,&#xA;  [&#xA;    // input audio by pipe&#xA;    "-thread_queue_size", "4096",&#xA;    "-i", "pipe:3",&#xA;&#xA;    // input video by pipe&#xA;    "-thread_queue_size", "4096",&#xA;    "-r", "60",&#xA;    "-i", "pipe:4",&#xA;&#xA;    // map audio and video correspondingly&#xA;    "-map", "0:a",&#xA;    "-map", "1:v",&#xA;&#xA;    // change the codec&#xA;    "-c:v", "libx264", &#xA;    "-c:a", "aac",&#xA;        &#xA;    "-preset", "ultrafast",&#xA;&#xA;    // Allow output to be seekable, which is needed for mp4 output&#xA;    "-movflags", "frag_keyframe&#x2B;empty_moov",&#xA;&#xA;    // output mp4 and pipe&#xA;    "-r", "60",&#xA;    "-fflags", "&#x2B;genpts",&#xA;    "-f", "mp4", "pipe:5",&#xA;  ],&#xA;  {&#xA;    // no popup window for Windows users&#xA;    windowsHide: true,&#xA;    stdio: [&#xA;      // silence stdin/out, forward stderr,&#xA;      "inherit", "inherit", "inherit",&#xA;      // and pipe audio, video, output&#xA;      "pipe", "pipe", "pipe",&#xA;    ],&#xA;  }&#xA;);&#xA;audioStream.pipe(ffmpegProcess.stdio[3]);&#xA;videoStream.pipe(ffmpegProcess.stdio[4]);&#xA;ffmpegProcess.stdio[5].pipe(result);

    &#xD;&#xA;

    &#xD;&#xA;

    &#xD;&#xA;&#xA;

    Full console output :

    &#xA;

    ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers        &#xA;  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)&#xA;  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp &#xA;--enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx &#xA;--enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband&#xA;  libavutil      57. 17.100 / 57. 17.100&#xA;  libavcodec     59. 18.100 / 59. 18.100&#xA;  libavformat    59. 16.100 / 59. 16.100&#xA;  libavdevice    59.  4.100 / 59.  4.100&#xA;  libavfilter     8. 24.100 /  8. 24.100&#xA;  libswscale      6.  4.100 /  6.  4.100&#xA;  libswresample   4.  3.100 /  4.  3.100&#xA;  libpostproc    56.  3.100 / 56.  3.100&#xA;Input #0, mov,mp4,m4a,3gp,3g2,mj2, from &#x27;pipe:3&#x27;:&#xA;  Metadata:&#xA;    major_brand     : mp42&#xA;    minor_version   : 0&#xA;    compatible_brands: isommp42&#xA;    creation_time   : 2022-08-21T19:56:49.000000Z&#xA;  Duration: 00:01:32.11, start: 0.000000, bitrate: N/A&#xA;  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 1892 kb/s, 30 fps, 30 tbr, 15360 tbn (default)&#xA;    Metadata:&#xA;      creation_time   : 2022-08-21T19:56:49.000000Z&#xA;      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.&#xA;      vendor_id       : [0][0][0][0]&#xA;  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)    Metadata:&#xA;      creation_time   : 2022-08-21T19:56:49.000000Z&#xA;      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.&#xA;      vendor_id       : [0][0][0][0]&#xA;Input #1, matroska,webm, from &#x27;pipe:4&#x27;:&#xA;  Metadata:&#xA;    encoder         : google/video-file&#xA;  Duration: 00:01:32.12, start: 0.000000, bitrate: N/A&#xA;  Stream #1:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 3840x2160, SAR 1:1 DAR 16:9, 60 fps, 60 &#xA;tbr, 1k tbn (default)&#xA;Stream mapping:&#xA;  Stream #0:1 -> #0:0 (aac (native) -> aac (native))&#xA;  Stream #1:0 -> #0:1 (vp9 (native) -> h264 (libx264))&#xA;[libx264 @ 0000022aa059be80] using SAR=1/1&#xA;[libx264 @ 0000022aa059be80] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2      &#xA;[libx264 @ 0000022aa059be80] profile Constrained Baseline, level 5.2, 4:2:0, 8-bit&#xA;[libx264 @ 0000022aa059be80] 264 - core 164 r3094 bfc87b7 - H.264/MPEG-4 AVC codec - Copyleft 2003-2022 &#xA;- http://www.videolan.org/x264.html - options: cabac=0 ref=1 deblock=0:0:0 analyse=0:0 me=dia subme=0 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=250 keyint_min=25 scenecut=0 intra_refresh=0 rc=crf mbtree=0 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=0&#xA;Output #0, mp4, to &#x27;pipe:5&#x27;:&#xA;  Metadata:&#xA;    major_brand     : mp42&#xA;    minor_version   : 0&#xA;    compatible_brands: isommp42&#xA;    encoder         : Lavf59.16.100&#xA;  Stream #0:0(eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)     &#xA;    Metadata:&#xA;      creation_time   : 2022-08-21T19:56:49.000000Z&#xA;      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.&#xA;      vendor_id       : [0][0][0][0]&#xA;      encoder         : Lavc59.18.100 aac&#xA;  Stream #0:1(eng): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160 [SAR 1:1 DAR 16:9], q=2-31, 60 fps, 15360 tbn (default)&#xA;    Metadata:&#xA;      encoder         : Lavc59.18.100 libx264&#xA;    Side data:&#xA;      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A&#xA;[matroska,webm @ 0000022aa056cd00] Thread message queue blocking; consider raising the thread_queue_size option (current value: 4096)&#xA;frame= 5527 fps= 77 q=-1.0 Lsize=  424599kB time=00:01:32.11 bitrate=37761.2kbits/s speed=1.29x    &#xA;video:423226kB audio:1329kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.010570%[aac @ 0000022aa05ca240] Qavg: 17828.035&#xA;[libx264 @ 0000022aa059be80] frame I:23    Avg QP:19.83  size:292044&#xA;[libx264 @ 0000022aa059be80] frame P:5504  Avg QP:22.92  size: 77519&#xA;[libx264 @ 0000022aa059be80] mb I  I16..4: 100.0%  0.0%  0.0%&#xA;[libx264 @ 0000022aa059be80] mb P  I16..4: 26.5%  0.0%  0.0%  P16..4: 14.1%  0.0%  0.0%  0.0%  0.0%    skip:59.3%&#xA;[libx264 @ 0000022aa059be80] coded y,uvDC,uvAC intra: 10.6% 27.6% 7.0% inter: 6.5% 12.8% 1.4%&#xA;[libx264 @ 0000022aa059be80] i16 v,h,dc,p: 57% 26%  8%  9%&#xA;[libx264 @ 0000022aa059be80] i8c dc,h,v,p: 43% 24% 25%  7%&#xA;[libx264 @ 0000022aa059be80] kb/s:37637.70&#xA;

    &#xA;

  • Decoding audio via Android using FFMpeg

    31 octobre 2013, par Rob Haupt

    I can play Wav files using the below code without issues. When trying to play the exact same media in Mp3 format I only get garbled junk. I believe I am fundamentally misunderstanding how the avcodec_decode_audio3 function works.

    Since the Wav file contains PCM data when it is decoded it can go straight to the AudioTrack.write function. There must be some additional step to get Mp3s to work like this. I don't know what I'm missing, but I've been pulling my hair out for a week now.

    Java Code

    package com.rohaupt.RRD2;

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    import android.app.Activity;
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioTrack;
    import android.media.MediaPlayer;
    import android.os.Bundle;
    import android.os.SystemClock;

    public class player extends Activity
    {
       private AudioTrack track;
       private FileOutputStream os;
       /** Called when the activity is first created. */
       @Override
       public void onCreate(Bundle savedInstanceState)
       {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.main);
           createEngine();

           MediaPlayer mp = new MediaPlayer();
           mp.start();

           int bufSize = AudioTrack.getMinBufferSize(32000,
                                                     AudioFormat.CHANNEL_CONFIGURATION_STEREO,
                                                     AudioFormat.ENCODING_PCM_16BIT);


           track = new AudioTrack(AudioManager.STREAM_MUSIC,
                                  32000,
                                  AudioFormat.CHANNEL_CONFIGURATION_STEREO,
                                  AudioFormat.ENCODING_PCM_16BIT,
                                  bufSize,
                                  AudioTrack.MODE_STREAM);

           byte[] bytes = new byte[bufSize];

           try {
               os = new FileOutputStream("/sdcard/a.out",false);
           } catch (FileNotFoundException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }

           String result = loadFile("/sdcard/a.mp3",bytes);

           try {
               os.close();
           } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
       }

       void playSound(byte[] buf, int size) {  
           //android.util.Log.v("ROHAUPT", "RAH Playing");
           if(track.getPlayState()!=AudioTrack.PLAYSTATE_PLAYING)
               track.play();
           track.write(buf, 0, size);

           try {
               os.write(buf,0,size);
           } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
       }


       private native void createEngine();
       private native String loadFile(String file, byte[] array);

       /** Load jni .so on initialization*/
       static {
            System.loadLibrary("avutil");
            System.loadLibrary("avcore");
            System.loadLibrary("avcodec");
            System.loadLibrary("avformat");
            System.loadLibrary("avdevice");
            System.loadLibrary("swscale");
            System.loadLibrary("avfilter");
            System.loadLibrary("ffmpeg");
       }
    }

    C Code

    #include
    #include
    #include
    #include <android></android>log.h>

    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"

    #define DEBUG_TAG "ROHAUPT"  

    void Java_com_rohaupt_RRD2_player_createEngine(JNIEnv* env, jclass clazz)
       {
           avcodec_init();

           av_register_all();


       }

       jstring Java_com_rohaupt_RRD2_player_loadFile(JNIEnv* env, jobject obj,jstring file,jbyteArray array)
       {  
           jboolean            isCopy;  
           int                 i;
           int                 audioStream=-1;
           int                 res;
           int                 decoded = 0;
           int                 out_size;
           AVFormatContext     *pFormatCtx;
           AVCodecContext      *aCodecCtx;
           AVCodecContext      *c= NULL;
           AVCodec             *aCodec;
           AVPacket            packet;
           jclass              cls = (*env)->GetObjectClass(env, obj);
           jmethodID           play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");//At the begining of your main function
           const char *        szfile = (*env)->GetStringUTFChars(env, file, &amp;isCopy);
           int16_t *           pAudioBuffer = (int16_t *) av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE*2+FF_INPUT_BUFFER_PADDING_SIZE);
           int16_t *           outBuffer = (int16_t *) av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE*2+FF_INPUT_BUFFER_PADDING_SIZE);


           __android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "RAH28 Starting");
           res = av_open_input_file(&amp;pFormatCtx, szfile, NULL, 0, NULL);
           if(res!=0)
           {
               __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH opening input failed with result: [%d]", res);
               return file;
           }

           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH getting stream info");
           res = av_find_stream_info(pFormatCtx);
           if(res&lt;0)
           {
               __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH getting stream info failed with result: [%d]", res);
               return file;
           }

           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH getting audio stream");
           for(i=0; i &lt; pFormatCtx->nb_streams; i++) {
             if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &amp;&amp;
                audioStream &lt; 0) {
               audioStream=i;
             }
           }


           if(audioStream==-1)
           {
               __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH couldn&#39;t find audio stream");
               return file;
           }
           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio stream found with result: [%d]", res);


           aCodecCtx=pFormatCtx->streams[audioStream]->codec;
           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio codec info loaded");

           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio codec info [%d]", aCodecCtx->codec_id);

           aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
           if(!aCodec) {
              __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio codec unsupported");
              return file;
           }
           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio codec info found");


           res = avcodec_open(aCodecCtx, aCodec);
           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio codec loaded [%d] [%d]",aCodecCtx->sample_fmt,res);

           //c=avcodec_alloc_context();
           av_init_packet(&amp;packet);


           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH channels [%d] sample rate [%d] sample format [%d]",aCodecCtx->channels,aCodecCtx->sample_rate,aCodecCtx->sample_fmt);


           int x,y;
           x=0;y=0;
           while (av_read_frame(pFormatCtx, &amp;packet)>= 0) {
               __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH frame read: [%d] [%d]",x++,y);

               if (aCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {
                           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH audio ready");
                           int data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*2+FF_INPUT_BUFFER_PADDING_SIZE;
                           int size=packet.size;
                           y=0;
                           decoded = 0;
                           __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH packet size: [%d]", size);
                           while(size > 0) {

                                   __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH decoding: [%d] [%d]",x,y++);
                                   int len = avcodec_decode_audio3(aCodecCtx, pAudioBuffer, &amp;data_size, &amp;packet);



                                   __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH 1 size [%d] len [%d] data_size [%d] out_size [%d]",size,len,data_size,out_size);
                                   jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);

                                   memcpy(bytes + decoded, pAudioBuffer, len); //


                                   __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH 2");

                                   (*env)->ReleaseByteArrayElements(env, array, bytes, 0);
                                   __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH 3");

                                   (*env)->CallVoidMethod(env, obj, play, array, len);

                                   __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH 4");


                                   size -= len;
                                   decoded += len;

                          }
                          av_free_packet(&amp;packet);
               }

        }

             // Close the video file
           av_close_input_file(pFormatCtx);

           //__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "RAH Finished Running result: [%d]", res);
           (*env)->ReleaseStringUTFChars(env, file, szfile);  
           return file;  
       }

    To add some detail. When Calling this function with a Wav File I get the following Log Data

    I/ROHAUPT (  227): RAH28 Starting
    D/ROHAUPT (  227): RAH getting stream info
    D/ROHAUPT (  227): RAH getting audio stream
    D/ROHAUPT (  227): RAH audio stream found with result: [0]
    D/ROHAUPT (  227): RAH audio codec info loaded
    D/ROHAUPT (  227): RAH audio codec info [65536]
    D/ROHAUPT (  227): RAH audio codec info found
    D/ROHAUPT (  227): RAH audio codec loaded [1] [0]
    D/ROHAUPT (  227): RAH channels [2] sample rate [32000] sample format [1]
    D/ROHAUPT (  227): RAH frame read: [0] [0]
    D/ROHAUPT (  227): RAH audio ready
    D/ROHAUPT (  227): RAH packet size: [4096]
    D/ROHAUPT (  227): RAH decoding: [1] [0]
    D/ROHAUPT (  227): RAH 1 size [4096] len [4096] data_size [4096] out_size [0]
    D/ROHAUPT (  227): RAH 2
    D/ROHAUPT (  227): RAH 3
    D/ROHAUPT (  227): RAH 4
    D/ROHAUPT (  227): RAH frame read: [1] [1]
    D/ROHAUPT (  227): RAH audio ready
    ...
    D/ROHAUPT (  227): RAH frame read: [924] [1]
    D/ROHAUPT (  227): RAH audio ready
    D/ROHAUPT (  227): RAH packet size: [4096]
    D/ROHAUPT (  227): RAH decoding: [925] [0]
    D/ROHAUPT (  227): RAH 1 size [4096] len [4096] data_size [4096] out_size [0]
    D/ROHAUPT (  227): RAH 2
    D/ROHAUPT (  227): RAH 3
    D/ROHAUPT (  227): RAH 4
    D/ROHAUPT (  227): RAH frame read: [925] [1]
    D/ROHAUPT (  227): RAH audio ready
    D/ROHAUPT (  227): RAH packet size: [3584]
    D/ROHAUPT (  227): RAH decoding: [926] [0]
    D/ROHAUPT (  227): RAH 1 size [3584] len [3584] data_size [3584] out_size [0]
    D/ROHAUPT (  227): RAH 2
    D/ROHAUPT (  227): RAH 3
    D/ROHAUPT (  227): RAH 4

    When calling with an Mp3 file I get the following

    I/ROHAUPT (  280): RAH28 Starting
    D/ROHAUPT (  280): RAH getting stream info
    D/ROHAUPT (  280): RAH getting audio stream
    D/ROHAUPT (  280): RAH audio stream found with result: [0]
    D/ROHAUPT (  280): RAH audio codec info loaded
    D/ROHAUPT (  280): RAH audio codec info [86017]
    D/ROHAUPT (  280): RAH audio codec info found
    D/ROHAUPT (  280): RAH audio codec loaded [1] [0]
    D/ROHAUPT (  280): RAH channels [2] sample rate [32000] sample format [1]
    D/ROHAUPT (  280): RAH frame read: [0] [0]
    D/ROHAUPT (  280): RAH audio ready
    D/ROHAUPT (  280): RAH packet size: [432]
    D/ROHAUPT (  280): RAH decoding: [1] [0]
    D/ROHAUPT (  280): RAH 1 size [432] len [432] data_size [4608] out_size [0]
    D/ROHAUPT (  280): RAH 2
    ...
    D/ROHAUPT (  280): RAH frame read: [822] [1]
    D/ROHAUPT (  280): RAH audio ready
    D/ROHAUPT (  280): RAH packet size: [432]
    D/ROHAUPT (  280): RAH decoding: [823] [0]
    D/ROHAUPT (  280): RAH 1 size [432] len [432] data_size [4608] out_size [0]
    D/ROHAUPT (  280): RAH 2
    D/ROHAUPT (  280): RAH 3
    D/ROHAUPT (  280): RAH 4
    D/ROHAUPT (  280): RAH frame read: [823] [1]
    D/ROHAUPT (  280): RAH audio ready
    D/ROHAUPT (  280): RAH packet size: [432]
    D/ROHAUPT (  280): RAH decoding: [824] [0]
    D/ROHAUPT (  280): RAH 1 size [432] len [432] data_size [4608] out_size [0]
    D/ROHAUPT (  280): RAH 2
    D/ROHAUPT (  280): RAH 3
    D/ROHAUPT (  280): RAH 4