
Recherche avancée
Médias (1)
-
The pirate bay depuis la Belgique
1er avril 2013, par
Mis à jour : Avril 2013
Langue : français
Type : Image
Autres articles (90)
-
Les vidéos
21 avril 2011, parComme les documents de type "audio", Mediaspip affiche dans la mesure du possible les vidéos grâce à la balise html5 .
Un des inconvénients de cette balise est qu’elle n’est pas reconnue correctement par certains navigateurs (Internet Explorer pour ne pas le nommer) et que chaque navigateur ne gère en natif que certains formats de vidéos.
Son avantage principal quant à lui est de bénéficier de la prise en charge native de vidéos dans les navigateur et donc de se passer de l’utilisation de Flash et (...) -
Participer à sa traduction
10 avril 2011Vous pouvez nous aider à améliorer les locutions utilisées dans le logiciel ou à traduire celui-ci dans n’importe qu’elle nouvelle langue permettant sa diffusion à de nouvelles communautés linguistiques.
Pour ce faire, on utilise l’interface de traduction de SPIP où l’ensemble des modules de langue de MediaSPIP sont à disposition. ll vous suffit de vous inscrire sur la liste de discussion des traducteurs pour demander plus d’informations.
Actuellement MediaSPIP n’est disponible qu’en français et (...) -
Creating farms of unique websites
13 avril 2011, parMediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...)
Sur d’autres sites (9347)
-
FFMPEG exception in debug mode only
28 septembre 2015, par Ahmed-AnasSo I’m trying to use ffmpeg in c++. My code is like this :
#include <iostream>
extern "C"
{
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libswscale\swscale.h"
}
using namespace std;
#pragma comment(lib, "dev/lib/avcodec.lib")
#pragma comment(lib, "dev/lib/avformat.lib")
#pragma comment(lib, "dev/lib/swscale.lib")
int main()
{
avcodec_register_all();
av_register_all();
char inputFile[] = "video.mp4";
AVFormatContext *pFormatCtx;
if (avformat_open_input(&pFormatCtx, inputFile, NULL, 0) != 0) // exception occurs here
{
cout << "could not open file";
return -1;
}
}
</iostream>This code runs in release mode but in debug mode I get the exception at
avformat_open_input
:Unhandled exception at 0x0000000074BC3C35 (avformat-55.dll) in
ingrain.exe : 0xC0000005 : Access violation reading location
0xFFFFFFFFFFFFFFFF.I downloaded the dll’s and lib’s directely from ffmpeg’s site and included them in my visual studio 2012’s project.
Thank’s in advance.
-
How to stop os.system() in Python ?
30 septembre 2015, par 吴雨羲I want to stop the cmd command after 12 seconds. How to stop it ? My program doesn’t work.
import multiprocessing
import os
import time
def process():
os.system('ffmpeg -i rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp -c copy dump.mp4')
def stop():
time.sleep(12)
if __name__ == '__main__':
p = multiprocessing.Process(target=process, args=())
s = multiprocessing.Process(target=stop, args=())
p.start()
s.start()
s.join()
p.terminate()I change my program follow Pedro’s suggusetion @Pedro Lobito ,but it still doesn`t work.
import shlex
import subprocess
import time
command_line = 'ffmpeg -i rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp -c copy dump.mp4'
proc = subprocess.Popen(shlex.split(command_line), shell=True)
print '1' * 50
time.sleep(2) # <-- sleep for 12''
print '2' * 50
proc.terminate() # <-- terminate the process
print '3' * 50And the result in CMD is
D:\wyx\workspace\python\ffrstp>python test1.py
11111111111111111111111111111111111111111111111111
ffmpeg version N-75563-g235381e Copyright (c) 2000-2015 the FFmpeg developers
built with gcc 4.9.3 (GCC)
configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-av
isynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enab
le-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --
enable-libdcadec --enable-libfreetype --enable-libgme --enable-libgsm --enable-l
ibilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enab
le-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --en
able-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --ena
ble-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc
--enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enabl
e-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --ena
ble-decklink --enable-zlib
libavutil 55. 2.100 / 55. 2.100
libavcodec 57. 3.100 / 57. 3.100
libavformat 57. 2.100 / 57. 2.100
libavdevice 57. 0.100 / 57. 0.100
libavfilter 6. 8.100 / 6. 8.100
libswscale 4. 0.100 / 4. 0.100
libswresample 2. 0.100 / 2. 0.100
libpostproc 54. 0.100 / 54. 0.100
Input #0, rtsp, from 'rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwc
fbqjoo80j.sdp':
Metadata:
title : RTSP Session
comment : Jabsco Stream(JCO-jy9757acx1eve7nm-a104aea23c1e17bbc776656
f5069bbf7)
Duration: N/A, start: 0.000000, bitrate: N/A
Stream #0:0: Video: mpeg4 (Simple Profile), yuv420p, 352x288 [SAR 1:1 DAR 11
:9], 10k tbr, 90k tbn, 10k tbc
[mp4 @ 00bad520] Codec for stream 0 does not use global headers but container fo
rmat requires global headers
Output #0, mp4, to 'dump.mp4':
Metadata:
title : RTSP Session
comment : Jabsco Stream(JCO-jy9757acx1eve7nm-a104aea23c1e17bbc776656
f5069bbf7)
encoder : Lavf57.2.100
Stream #0:0: Video: mpeg4 ( [0][0][0] / 0x0020), yuv420p, 352x288 [SAR 1:1 D
AR 11:9], q=2-31, 10k tbr, 90k tbn, 90k tbc
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
[mp4 @ 00bad520] pts has no value
[mp4 @ 00bad520] Non-monotonous DTS in output stream 0:0; previous: 0, current:
0; changing to 1. This may result in incorrect timestamps in the output file.
[mp4 @ 00bad520] Non-monotonous DTS in output stream 0:0; previous: 1, current:
0; changing to 2. This may result in incorrect timestamps in the output file.
frame= 30 fps=0.0 q=-1.0 size= 63kB time=00:00:02.33 bitrate= 220.4kbits/
frame= 36 fps= 31 q=-1.0 size= 68kB time=00:00:02.95 bitrate= 187.9kbits/
frame= 42 fps= 24 q=-1.0 size= 73kB time=00:00:03.52 bitrate= 169.6kbits/
frame= 47 fps= 20 q=-1.0 size= 90kB time=00:00:04.10 bitrate= 178.9kbits/
frame= 53 fps= 19 q=-1.0 size= 95kB time=00:00:04.63 bitrate= 167.2kbits/
22222222222222222222222222222222222222222222222222
33333333333333333333333333333333333333333333333333
D:\wyx\workspace\python\ffrstp>frame= 58 fps= 17 q=-1.0 size= 99kB time=0
frame= 64 fps= 16 q=-1.0 size= 104kB time=00:00:05.72 bitrate= 149.0kbits/
frame= 70 fps= 15 q=-1.0 size= 122kB time=00:00:06.36 bitrate= 156.7kbits/
frame= 76 fps= 15 q=-1.0 size= 127kB time=00:00:06.92 bitrate= 150.2kbits/
frame= 82 fps= 14 q=-1.0 size= 132kB time=00:00:07.55 bitrate= 143.2kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 7 packets
frame= 86 fps= 13 q=-1.0 size= 135kB time=00:00:07.95 bitrate= 139.5kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 3 packetsMaybe ffmpeg can reconnection. Can I stop it like ’Ctrl + C’ ?
When I press ’Ctrl+C’,the result is22222222222222222222222222222222222222222222222222
33333333333333333333333333333333333333333333333333
D:\wyx\workspace\python\ffrstp>frame= 58 fps= 17 q=-1.0 size= 99kB time=0
frame= 64 fps= 16 q=-1.0 size= 104kB time=00:00:05.72 bitrate= 149.0kbits/
frame= 70 fps= 15 q=-1.0 size= 122kB time=00:00:06.36 bitrate= 156.7kbits/
frame= 76 fps= 15 q=-1.0 size= 127kB time=00:00:06.92 bitrate= 150.2kbits/
frame= 82 fps= 14 q=-1.0 size= 132kB time=00:00:07.55 bitrate= 143.2kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 7 packets
frame= 86 fps= 13 q=-1.0 size= 135kB time=00:00:07.95 bitrate= 139.5kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 3 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 1 packets
frame= 89 fps= 13 q=-1.0 size= 138kB time=00:00:08.35 bitrate= 135.3kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 1 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 3 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 5 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 3 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 1 packets
frame= 92 fps= 12 q=-1.0 size= 144kB time=00:00:09.15 bitrate= 128.7kbits/
frame= 93 fps= 11 q=-1.0 size= 145kB time=00:00:09.58 bitrate= 123.8kbits/
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 1 packets
[rtsp @ 00adb3e0] max delay reached. need to consume packet
[NULL @ 00add8c0] RTP: missed 2 packets
D:\wyx\workspace\python\ffrstp>[rtsp @ 00adb3e0] max delay reached. need to cons
ume packet
[NULL @ 00add8c0] RTP: missed 12 packets
frame= 96 fps= 11 q=-1.0 size= 148kB time=00:00:10.43 bitrate= 116.2kbits/
frame= 96 fps=9.2 q=-1.0 Lsize= 151kB time=00:00:10.43 bitrate= 118.3kbits
/s
video:148kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing o
verhead: 1.913398%
Exiting normally, received signal 2. -
Trying to cancel execution and delete file using ffmpeg C API
6 mars 2020, par VuwoxThe code below is a class that handle the conversion of multiples images, through
add_frame()
method, into a GIF withencode()
. It also use a filter to generate and apply the palette. The usage is like this :Code call example
std::unique_ptr gif_obj = nullptr;
try
{
gif_obj = std::make_unique({1000,1000}, 12, "C:/out.gif",
"format=pix_fmts=rgb24,split [a][b];[a]palettegen[p];[b][p]paletteuse");
// Example: a simple vector of images (usually process internally)
for(auto img : image_vector)
gif_obj->add_frame(img);
// Once all frame were added, encode the final GIF with the filter applied.
gif_obj->encode();
}
catch(const std::exception& e)
{
// An error occured! We must close FFMPEG properly and delete the created file.
gif_obj->cancel();
}I have the following issue. If the code for any reason throw an exception, I call
ffmpeg->cancel()
and it supposes to delete the GIF file on disk. But this is never working, I assume there is a lock on the file or something like that. So here are my question :What is the proper way to close/free ffmpeg object in order to remove the file afterward ?
Full class code below
Header
// C++ Standard includes
#include <memory>
#include <string>
#include <vector>
// 3rd Party incldues
#ifdef __cplusplus
extern "C" {
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavutil/opt.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
}
#endif
#define FFMPEG_MSG_LEN 2000
namespace px
{
namespace GIF
{
class FFMPEG
{
public:
FFMPEG(const px::Point2D<int>& dim,
const int framerate,
const std::string& filename,
const std::string& filter_cmd);
~FFMPEG();
void add_frame(pxImage * const img);
void encode();
void cancel();
private:
void init_filters(); // Init everything that needed to filter the input frame.
void init_muxer(); // The muxer that creates the output file.
void muxing_one_frame(AVFrame* frame);
void release();
int _ret = 0; // status code from FFMPEG.
char _err_msg[FFMPEG_MSG_LEN]; // Error message buffer.
int m_width = 0; // The width that all futur images must have to be accepted.
int m_height = 0; // The height that all futur images must have to be accepted.
int m_framerate = 0; // GIF Framerate.
std::string m_filename = ""; // The GIF filename (on cache?)
std::string m_filter_desc = ""; // The FFMPEG filter to apply over the frames.
bool as_frame = false;
AVFrame* picture_rgb24 = nullptr; // Temporary frame that will hold the pxImage in an RGB24 format (NOTE: TOP-LEFT origin)
AVFormatContext* ofmt_ctx = nullptr; // ouput format context associated to the
AVCodecContext* o_codec_ctx = nullptr; // output codec for the GIF
AVFilterGraph* filter_graph = nullptr; // filter graph associate with the string we want to execute
AVFilterContext* buffersrc_ctx = nullptr; // The buffer that will store all the frames in one place for the palette generation.
AVFilterContext* buffersink_ctx = nullptr; // The buffer that will store the result afterward (once the palette are used).
int64_t m_pts_increment = 0;
};
};
};
</int></vector></string></memory>ctor
px::GIF::FFMPEG::FFMPEG(const px::Point2D<int>& dim,
const int framerate,
const std::string& filename,
const std::string& filter_cmd) :
m_width(dim.x()),
m_height(dim.y()),
m_framerate(framerate),
m_filename(filename),
m_filter_desc(filter_cmd)
{
#if !_DEBUG
av_log_set_level(AV_LOG_QUIET); // Set the FFMPEG log to quiet to avoid too much logs.
#endif
// Allocate the temporary buffer that hold the ffmpeg image (pxImage to AVFrame conversion).
picture_rgb24 = av_frame_alloc();
picture_rgb24->pts = 0;
picture_rgb24->data[0] = NULL;
picture_rgb24->linesize[0] = -1;
picture_rgb24->format = AV_PIX_FMT_RGB24;
picture_rgb24->height = m_height;
picture_rgb24->width = m_width;
if ((_ret = av_image_alloc(picture_rgb24->data, picture_rgb24->linesize, m_width, m_height, (AVPixelFormat)picture_rgb24->format, 24)) < 0)
throw px::GIF::Error("Failed to allocate the AVFrame for pxImage conversion with error: " +
std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)),
"GIF::FFMPEG CTOR");
//printf("allocated picture of size %d, linesize %d %d %d %d\n", _ret, picture_rgb24->linesize[0], picture_rgb24->linesize[1], picture_rgb24->linesize[2], picture_rgb24->linesize[3]);
init_muxer(); // Prepare the GIF encoder (open it on disk).
init_filters(); // Prepare the filter that will be applied over the frame.
// Instead of hardcoder {1,100} which is the GIF tbn, we collect it from its stream.
// This will avoid future problem if the codec change in ffmpeg.
if (ofmt_ctx && ofmt_ctx->nb_streams > 0)
m_pts_increment = av_rescale_q(1, { 1, m_framerate }, ofmt_ctx->streams[0]->time_base);
else
m_pts_increment = av_rescale_q(1, { 1, m_framerate }, { 1, 100 });
}
</int>FFMPEG Initialization (Filter and muxer)
void px::GIF::FFMPEG::init_filters()
{
const AVFilter* buffersrc = avfilter_get_by_name("buffer");
const AVFilter* buffersink = avfilter_get_by_name("buffersink");
AVRational time_base = { 1, m_framerate };
AVRational aspect_pixel = { 1, 1 };
AVFilterInOut* inputs = avfilter_inout_alloc();
AVFilterInOut* outputs = avfilter_inout_alloc();
filter_graph = avfilter_graph_alloc();
try
{
if (!outputs || !inputs || !filter_graph)
throw px::GIF::Error("Failed to 'init_filters' could not allocated the graph/filters.", "GIF::FFMPEG init_filters");
char args[512];
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
m_width, m_height,
picture_rgb24->format,
time_base.num, time_base.den,
aspect_pixel.num, aspect_pixel.den);
if (avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, nullptr, filter_graph) < 0)
throw px::GIF::Error("Failed to create the 'source buffer' in init_filer method.", "GIF::FFMPEG init_filters");
if (avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", nullptr, nullptr, filter_graph) < 0)
throw px::GIF::Error("Failed to create the 'sink buffer' in init_filer method.", "GIF::FFMPEG init_filters");
// GIF has possible output of PAL8.
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE };
if (av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN) < 0)
throw px::GIF::Error("Failed to set the output pixel format.", "GIF::FFMPEG init_filters");
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = nullptr;
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = nullptr;
// GIF has possible output of PAL8.
if (avfilter_graph_parse_ptr(filter_graph, m_filter_desc.c_str(), &inputs, &outputs, nullptr) < 0)
throw px::GIF::Error("Failed to parse the filter graph (bad string!).", "GIF::FFMPEG init_filters");
if (avfilter_graph_config(filter_graph, nullptr) < 0)
throw px::GIF::Error("Failed to configure the filter graph (bad string!).", "GIF::FFMPEG init_filters");
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
}
catch (const std::exception& e)
{
// Catch exception to delete element.
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
throw e; // re-throuw
}
}
void px::GIF::FFMPEG::init_muxer()
{
AVOutputFormat* o_fmt = av_guess_format("gif", m_filename.c_str(), "video/gif");
if ((_ret = avformat_alloc_output_context2(&ofmt_ctx, o_fmt, "gif", m_filename.c_str())) < 0)
throw px::GIF::Error(std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)) + " allocate output format.", "GIF::FFMPEG init_muxer");
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_GIF);
if (!codec) throw px::GIF::Error("Could to find the 'GIF' codec.", "GIF::FFMPEG init_muxer");
#if 0
const AVPixelFormat* p = codec->pix_fmts;
while (p != NULL && *p != AV_PIX_FMT_NONE) {
printf("supported pix fmt: %s\n", av_get_pix_fmt_name(*p));
++p;
}
#endif
AVStream* stream = avformat_new_stream(ofmt_ctx, codec);
AVCodecParameters* codec_paramters = stream->codecpar;
codec_paramters->codec_tag = 0;
codec_paramters->codec_id = codec->id;
codec_paramters->codec_type = AVMEDIA_TYPE_VIDEO;
codec_paramters->width = m_width;
codec_paramters->height = m_height;
codec_paramters->format = AV_PIX_FMT_PAL8;
o_codec_ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(o_codec_ctx, codec_paramters);
o_codec_ctx->time_base = { 1, m_framerate };
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
o_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if ((_ret = avcodec_open2(o_codec_ctx, codec, NULL)) < 0)
throw px::GIF::Error(std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)) + " open output codec.", "GIF::FFMPEG init_muxer");
if ((_ret = avio_open(&ofmt_ctx->pb, m_filename.c_str(), AVIO_FLAG_WRITE)) < 0)
throw px::GIF::Error(std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)) + " avio open error.", "GIF::FFMPEG init_muxer");
if ((_ret = avformat_write_header(ofmt_ctx, NULL)) < 0)
throw px::GIF::Error(std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)) + " write GIF header", "GIF::FFMPEG init_muxer");
#if _DEBUG
// This print the stream/output format.
av_dump_format(ofmt_ctx, -1, m_filename.c_str(), 1);
#endif
}Add frame (usually in a loop)
void px::GIF::FFMPEG::add_frame(pxImage * const img)
{
if (img->getImageType() != PXT_BYTE || img->getNChannels() != 4)
throw px::GIF::Error("Failed to 'add_frame' since image is not PXT_BYTE and 4-channels.", "GIF::FFMPEG add_frame");
if (img->getWidth() != m_width || img->getHeight() != m_height)
throw px::GIF::Error("Failed to 'add_frame' since the size is not same to other inputs.", "GIF::FFMPEG add_frame");
const int pitch = picture_rgb24->linesize[0];
auto px_ptr = getImageAccessor(img);
for (int y = 0; y < m_height; y++)
{
const int px_row = img->getOrigin() == ORIGIN_BOT_LEFT ? m_height - y - 1 : y;
for (int x = 0; x < m_width; x++)
{
const int idx = y * pitch + 3 * x;
picture_rgb24->data[0][idx] = px_ptr[px_row][x].ch[PX_RE];
picture_rgb24->data[0][idx + 1] = px_ptr[px_row][x].ch[PX_GR];
picture_rgb24->data[0][idx + 2] = px_ptr[px_row][x].ch[PX_BL];
}
}
// palettegen need a whole stream, just add frame to buffer.
if ((_ret = av_buffersrc_add_frame_flags(buffersrc_ctx, picture_rgb24, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0)
throw px::GIF::Error("Failed to 'add_frame' to global buffer with error: " +
std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)),
"GIF::FFMPEG add_frame");
// Increment the FPS of the picture for the next add-up to the buffer.
picture_rgb24->pts += m_pts_increment;
as_frame = true;
}Encoder (final step)
void px::GIF::FFMPEG::encode()
{
if (!as_frame)
throw px::GIF::Error("Please 'add_frame' before running the Encoding().", "GIF::FFMPEG encode");
// end of buffer
if ((_ret = av_buffersrc_add_frame_flags(buffersrc_ctx, nullptr, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0)
throw px::GIF::Error("error add frame to buffer source: " + std::string(av_make_error_string(_err_msg, FFMPEG_MSG_LEN, _ret)), "GIF::FFMPEG encode");
do {
AVFrame* filter_frame = av_frame_alloc();
_ret = av_buffersink_get_frame(buffersink_ctx, filter_frame);
if (_ret == AVERROR(EAGAIN) || _ret == AVERROR_EOF) {
av_frame_unref(filter_frame);
break;
}
// write the filter frame to output file
muxing_one_frame(filter_frame);
av_frame_unref(filter_frame);
} while (_ret >= 0);
av_write_trailer(ofmt_ctx);
}
void px::GIF::FFMPEG::muxing_one_frame(AVFrame* frame)
{
int ret = avcodec_send_frame(o_codec_ctx, frame);
AVPacket *pkt = av_packet_alloc();
av_init_packet(pkt);
while (ret >= 0) {
ret = avcodec_receive_packet(o_codec_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
av_write_frame(ofmt_ctx, pkt);
}
av_packet_unref(pkt);
}DTOR, Release and Cancel
px::GIF::FFMPEG::~FFMPEG()
{
release();
}
void px::GIF::FFMPEG::release()
{
// Muxer stuffs
if (ofmt_ctx != nullptr) avformat_free_context(ofmt_ctx);
if (o_codec_ctx != nullptr) avcodec_close(o_codec_ctx);
if (o_codec_ctx != nullptr) avcodec_free_context(&o_codec_ctx);
ofmt_ctx = nullptr;
o_codec_ctx = nullptr;
// Filter stuffs
if (buffersrc_ctx != nullptr) avfilter_free(buffersrc_ctx);
if (buffersink_ctx != nullptr) avfilter_free(buffersink_ctx);
if (filter_graph != nullptr) avfilter_graph_free(&filter_graph);
buffersrc_ctx = nullptr;
buffersink_ctx = nullptr;
filter_graph = nullptr;
// Conversion image.
if (picture_rgb24 != nullptr) av_frame_free(&picture_rgb24);
picture_rgb24 = nullptr;
}
void px::GIF::FFMPEG::cancel()
{
// In-case of failure we must close ffmpeg and exit.
av_write_trailer(ofmt_ctx);
// Release and close all elements.
release();
// Delete the file on disk.
if (remove(m_filename.c_str()) != 0)
PX_LOG0(PX_LOGLEVEL_ERROR, "GIF::FFMPEG - On 'cancel' failed to remove the file.");
}