
Recherche avancée
Médias (1)
-
Rennes Emotion Map 2010-11
19 octobre 2011, par
Mis à jour : Juillet 2013
Langue : français
Type : Texte
Autres articles (51)
-
Submit bugs and patches
13 avril 2011Unfortunately 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 (...) -
Contribute to translation
13 avril 2011You 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 (...) -
Initialisation de MediaSPIP (préconfiguration)
20 février 2010, parLors de l’installation de MediaSPIP, celui-ci est préconfiguré pour les usages les plus fréquents.
Cette préconfiguration est réalisée par un plugin activé par défaut et non désactivable appelé MediaSPIP Init.
Ce plugin sert à préconfigurer de manière correcte chaque instance de MediaSPIP. Il doit donc être placé dans le dossier plugins-dist/ du site ou de la ferme pour être installé par défaut avant de pouvoir utiliser le site.
Dans un premier temps il active ou désactive des options de SPIP qui ne le (...)
Sur d’autres sites (8591)
-
Main process is held by ffmpeg command
6 octobre 2024, par Michael LopezI created a python program for handling my Arlo Camera. To do that I have been using the
pyaarlo
library (https://github.com/twrecked/pyaarlo) to catch camera's events.
The goal is to monitor if there is an active stream on cameras, get the RTSP stream url and reStream it to a HLS playlist for local usage.

Here the python code :


import asyncio
from decouple import config
import logging
from my_pyaarlo import PyArlo
import urllib.parse
from queue import Queue
import signal

# Read config from ENV (unchanged)
ARLO_USER = config('ARLO_USER')
ARLO_PASS = config('ARLO_PASS')
IMAP_HOST = config('IMAP_HOST')
IMAP_USER = config('IMAP_USER')
IMAP_PASS = config('IMAP_PASS')
DEBUG = config('DEBUG', default=False, cast=bool)
PYAARLO_BACKEND = config('PYAARLO_BACKEND', default=None)
PYAARLO_REFRESH_DEVICES = config('PYAARLO_REFRESH_DEVICES', default=0, cast=int)
PYAARLO_STREAM_TIMEOUT = config('PYAARLO_STREAM_TIMEOUT', default=0, cast=int)
PYAARLO_STORAGE_DIR = config('PYAARLO_STORAGE_DIR', default=None)
PYAARLO_ECDH_CURVE = config('PYAARLO_ECDH_CURVE', default=None)

# Initialize logging
logging.basicConfig(
 level=logging.DEBUG if DEBUG else logging.INFO,
 format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
logger = logging.getLogger(__name__)

ffmpeg_processes = {}
event_queue = Queue()
shutdown_event = asyncio.Event()

async def handle_idle_event(camera):
 logger.info(f"Idle event detected for camera: {camera.name}")
 await stop_ffmpeg_stream(camera.name)

async def get_stream_url(camera):
 try:
 # Attempt to get the stream URL
 stream_url = await asyncio.to_thread(camera.get_stream()
 if stream_url:
 return stream_url
 else:
 logger.warning(f"Unable to get stream URL for {camera.name}. Stream might not be active.")
 return None
 except Exception as e:
 logger.error(f"Error getting stream URL for {camera.name}: {e}")
 return None

async def handle_user_stream_active_event(camera):
 logger.info(f"User stream active event detected for camera: {camera.name}")

 # Get the stream URL
 stream_url = await get_stream_url(camera)
 if stream_url:
 logger.info(f"Stream URL for {camera.name}: {stream_url}")
 await start_ffmpeg_stream(camera.name, stream_url)
 else:
 logger.warning(f"No stream URL available for {camera.name}")

async def event_handler(device, attr, value):
 logger.debug(f"Event: {device.name}, Attribute: {attr}, Value: {value}")
 if attr == 'activityState':
 if value == 'idle':
 await handle_idle_event(device)
 elif value in ['userStreamActive']:
 await handle_user_stream_active_event(device)
 elif attr == 'mediaUploadNotification':
 logger.info(f"Media uploaded for camera: {device.name}")

def sync_event_handler(device, attr, value):
 # This function will be called by PyArlo's synchronous callbacks
 event_queue.put((device, attr, value))

async def process_event_queue():
 while not shutdown_event.is_set():
 try:
 if not event_queue.empty():
 device, attr, value = event_queue.get()
 await event_handler(device, attr, value)
 await asyncio.sleep(0.1) # Small delay to prevent busy-waiting
 except asyncio.CancelledError:
 break
 except Exception as e:
 logger.error(f"Error processing event: {e}")

async def display_status(arlo):
 while not shutdown_event.is_set():
 print("\n--- Camera Statuses ---")
 for camera in arlo.cameras:
 print(f"{camera.name}: {camera.state}")
 print("------------------------")
 await asyncio.sleep(5)

async def start_ffmpeg_stream(camera_name, stream_url):
 if camera_name not in ffmpeg_processes:
 output_hls = f"/tmp/{camera_name}.m3u8"

 try:
 new_url = urllib.parse.quote(stream_url.encode(), safe=':/?&=')
 logger.info(f"NEW_URL: {new_url}")

 ffmpeg_cmd = [
 "ffmpeg", "-hide_banner", "-loglevel", "quiet", "-nostats", "-nostdin", "-y", "-re",
 "-i", new_url,
 "-c:v", "libx264", "-preset", "veryfast",
 "-an", "-sn",
 "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
 "-hls_flags", "delete_segments", output_hls,
 ]
 logger.info(f"Starting FFmpeg command: {ffmpeg_cmd}")
 
 process = await asyncio.create_subprocess_exec(
 *ffmpeg_cmd,
 stdout=asyncio.subprocess.DEVNULL,
 stderr=asyncio.subprocess.DEVNULL
 )
 ffmpeg_processes[camera_name] = process
 logger.info(f"Started ffmpeg process with PID: {process.pid}")

 except Exception as e:
 logger.error(f"Error starting FFmpeg for {camera_name}: {e}")

async def stop_ffmpeg_stream(camera_name):
 logger.info(f"Stopping ffmpeg process for {camera_name}")
 ffmpeg_process = ffmpeg_processes.pop(camera_name, None)
 if ffmpeg_process:
 ffmpeg_process.terminate()

 try:
 await ffmpeg_process.wait()
 logger.info(f"{camera_name} stopped successfully")
 except Exception as e:
 print(f"FFMPEG Process didn't stop in time, forcefully terminating: {e}")
 ffmpeg_process.kill()
 else:
 logger.info(f"FFmpeg process for {camera_name} already stopped")

async def shutdown(signal, loop):
 logger.info(f"Received exit signal {signal.name}...")
 shutdown_event.set()
 tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
 [task.cancel() for task in tasks]
 logger.info(f"Cancelling {len(tasks)} outstanding tasks")
 await asyncio.gather(*tasks, return_exceptions=True)
 loop.stop()

async def main():
 # Initialize PyArlo
 arlo_args = {
 'username': ARLO_USER,
 'password': ARLO_PASS,
 'tfa_source': 'imap',
 'tfa_type': 'email',
 'tfa_host': IMAP_HOST,
 'tfa_username': IMAP_USER,
 'tfa_password': IMAP_PASS,
 'save_session': True,
 'verbose_debug': DEBUG
 }

 # Add optional arguments
 for arg, value in [
 ('refresh_devices_every', PYAARLO_REFRESH_DEVICES),
 ('stream_timeout', PYAARLO_STREAM_TIMEOUT),
 ('backend', PYAARLO_BACKEND),
 ('storage_dir', PYAARLO_STORAGE_DIR),
 ('ecdh_curve', PYAARLO_ECDH_CURVE)
 ]:
 if value:
 arlo_args[arg] = value
 
 try:
 arlo = await asyncio.to_thread(PyArlo, **arlo_args)
 except Exception as e:
 logger.error(f"Failed to initialize PyArlo: {e}")
 return

 logger.info("Connected to Arlo. Monitoring events...")

 # Register event handlers for each camera
 for camera in arlo.cameras:
 camera.add_attr_callback('*', sync_event_handler)

 # Start the status display task
 status_task = asyncio.create_task(display_status(arlo))

 # Start the event processing task
 event_processing_task = asyncio.create_task(process_event_queue())

 # Set up signal handlers
 loop = asyncio.get_running_loop()
 for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):
 loop.add_signal_handler(
 s, lambda s=s: asyncio.create_task(shutdown(s, loop)))

 try:
 # Keep the main coroutine running
 while not shutdown_event.is_set():
 try:
 await asyncio.sleep(1)
 except asyncio.CancelledError:
 break
 except Exception as e:
 logger.error(f"Unexpected error in main loop: {e}")
 finally:
 logger.info("Shutting down...")
 for camera_name in list(ffmpeg_processes.keys()):
 await stop_ffmpeg_stream(camera_name)
 
 # Cancel and wait for all tasks
 tasks = [status_task, event_processing_task]
 for task in tasks:
 if not task.done():
 task.cancel()
 await asyncio.gather(*tasks, return_exceptions=True)
 
 logger.info("Program terminated.")

if __name__ == "__main__":
 try:
 asyncio.run(main())
 except KeyboardInterrupt:
 logger.info("Keyboard interrupt received. Exiting.")
 except Exception as e:
 logger.error(f"Unhandled exception: {e}")
 finally:
 logger.info("Program exit complete.")



My issue is about the ffmpeg command which is hold the main process (or the event loop) when it runs, blocking the events coming from the pyaarlo library. The state of the camera continues to work with the good information.


I tried lot of things, without asyncio, with multiprocessing, with subprocess, ... the behavior is always the same. In some cases, I received the idle event after the key interrupt.


Another information :


- 

- When I stop the active stream, the event is not received but when I start the stream just after, that event is received.
- When I run the same ffmpeg command but with a local long video file, everything is Ok. So, it why I guess that the ffmpeg command is impacting the main process.






I succedeed in running the ffmpeg command with rtsp url stream but without a loop event monitoring :


import asyncio
import signal
import sys
import os

async def run_infinite_command():
 # Start a simple HTTP server as our "infinite" command
 url = "rstp://localhost:8554/camera1/stream" # it is a fake url
 ffmpeg_cmd = [
 "ffmpeg", "-re", "-i", url,
 "-c:v", "libx264", "-preset", "veryfast",
 "-c:a", "copy",
 "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
 "-hls_flags", "delete_segments", "/tmp/output.m3u8"
 ]
 
 process = await asyncio.create_subprocess_exec(
 *ffmpeg_cmd,
 stdout=asyncio.subprocess.DEVNULL,
 stderr=asyncio.subprocess.DEVNULL
 )
 
 print(f"Started HTTP server with PID: {process.pid}")
 return process

async def main():
 # Start the infinite command
 process = await run_infinite_command()

 # Run the main loop for a few seconds
 for i in range(10):
 print(f"Main loop iteration {i+1}")
 await asyncio.sleep(1)

 # Stop the infinite command
 print("Stopping the HTTP server...")
 if sys.platform == "win32":
 # On Windows, we need to use CTRL_C_EVENT
 os.kill(process.pid, signal.CTRL_C_EVENT)
 else:
 # On Unix-like systems, we can use SIGTERM
 process.send_signal(signal.SIGTERM)

 # Wait for the process to finish
 try:
 await asyncio.wait_for(process.wait(), timeout=5.0)
 print("HTTP server stopped successfully")
 except asyncio.TimeoutError:
 print("HTTP server didn't stop in time, forcefully terminating")
 process.kill()

 print("Program finished")

if __name__ == "__main__":
 asyncio.run(main())



With this script, the ffmpeg command is correctly launched and terminated after the for loop.


Could you help ?


-
Revision 33563 : spanish language file. May be we should use Salvatore, right ?
7 décembre 2009, par gaitan@… — Logspanish language file. May be we should use Salvatore, right ?
-
How to reparse video with stable "overall bit rate" ? (FFmpeg)
20 février 2018, par user3360601I have such code below :
#include
#include
#include
extern "C"
{
#include <libavcodec></libavcodec>avcodec.h>
#include <libavformat></libavformat>avformat.h>
#include <libavfilter></libavfilter>buffersink.h>
#include <libavfilter></libavfilter>buffersrc.h>
#include <libavutil></libavutil>opt.h>
#include <libavutil></libavutil>pixdesc.h>
}
static AVFormatContext *ifmt_ctx;
static AVFormatContext *ofmt_ctx;
typedef struct StreamContext {
AVCodecContext *dec_ctx;
AVCodecContext *enc_ctx;
} StreamContext;
static StreamContext *stream_ctx;
static int open_input_file(const char *filename)
{
int ret;
unsigned int i;
ifmt_ctx = NULL;
if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
return ret;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
return ret;
}
stream_ctx = (StreamContext *) av_mallocz_array(ifmt_ctx->nb_streams, sizeof(*stream_ctx));
if (!stream_ctx)
return AVERROR(ENOMEM);
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *stream = ifmt_ctx->streams[i];
AVCodec *dec = avcodec_find_decoder(stream->codecpar->codec_id);
AVCodecContext *codec_ctx;
if (!dec) {
av_log(NULL, AV_LOG_ERROR, "Failed to find decoder for stream #%u\n", i);
return AVERROR_DECODER_NOT_FOUND;
}
codec_ctx = avcodec_alloc_context3(dec);
if (!codec_ctx) {
av_log(NULL, AV_LOG_ERROR, "Failed to allocate the decoder context for stream #%u\n", i);
return AVERROR(ENOMEM);
}
ret = avcodec_parameters_to_context(codec_ctx, stream->codecpar);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to copy decoder parameters to input decoder context "
"for stream #%u\n", i);
return ret;
}
/* Reencode video & audio and remux subtitles etc. */
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
|| codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
codec_ctx->framerate = av_guess_frame_rate(ifmt_ctx, stream, NULL);
/* Open decoder */
ret = avcodec_open2(codec_ctx, dec, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);
return ret;
}
}
stream_ctx[i].dec_ctx = codec_ctx;
}
av_dump_format(ifmt_ctx, 0, filename, 0);
return 0;
}
static int open_output_file(const char *filename)
{
AVStream *out_stream;
AVStream *in_stream;
AVCodecContext *dec_ctx, *enc_ctx;
AVCodec *encoder;
int ret;
unsigned int i;
ofmt_ctx = NULL;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
if (!ofmt_ctx) {
av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
return AVERROR_UNKNOWN;
}
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
return AVERROR_UNKNOWN;
}
in_stream = ifmt_ctx->streams[i];
dec_ctx = stream_ctx[i].dec_ctx;
//ofmt_ctx->bit_rate = ifmt_ctx->bit_rate;
ofmt_ctx->duration = ifmt_ctx->duration;
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
|| dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
/* in this example, we choose transcoding to same codec */
encoder = avcodec_find_encoder(dec_ctx->codec_id);
if (!encoder) {
av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
return AVERROR_INVALIDDATA;
}
enc_ctx = avcodec_alloc_context3(encoder);
if (!enc_ctx) {
av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");
return AVERROR(ENOMEM);
}
/* In this example, we transcode to same properties (picture size,
* sample rate etc.). These properties can be changed for output
* streams easily using filters */
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
enc_ctx->gop_size = dec_ctx->gop_size;
enc_ctx->bit_rate = dec_ctx->bit_rate;
enc_ctx->height = dec_ctx->height;
enc_ctx->width = dec_ctx->width;
enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
/* take first format from list of supported formats */
if (encoder->pix_fmts)
enc_ctx->pix_fmt = encoder->pix_fmts[0];
else
enc_ctx->pix_fmt = dec_ctx->pix_fmt;
/* video time_base can be set to whatever is handy and supported by encoder */
enc_ctx->time_base = av_inv_q(dec_ctx->framerate);
enc_ctx->framerate = av_guess_frame_rate(ifmt_ctx, in_stream, NULL);
}
else {
enc_ctx->gop_size = dec_ctx->gop_size;
enc_ctx->bit_rate = dec_ctx->bit_rate;
enc_ctx->sample_rate = dec_ctx->sample_rate;
enc_ctx->channel_layout = dec_ctx->channel_layout;
enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
/* take first format from list of supported formats */
enc_ctx->sample_fmt = encoder->sample_fmts[0];
//enc_ctx->time_base = (AVRational){ 1, enc_ctx->sample_rate };
enc_ctx->time_base.num = 1;
enc_ctx->time_base.den = enc_ctx->sample_rate;
enc_ctx->framerate = av_guess_frame_rate(ifmt_ctx, in_stream, NULL);
}
/* Third parameter can be used to pass settings to encoder */
ret = avcodec_open2(enc_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
return ret;
}
ret = avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", i);
return ret;
}
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
out_stream->time_base = enc_ctx->time_base;
stream_ctx[i].enc_ctx = enc_ctx;
}
else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
return AVERROR_INVALIDDATA;
}
else {
/* if this stream must be remuxed */
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Copying parameters for stream #%u failed\n", i);
return ret;
}
out_stream->time_base = in_stream->time_base;
}
}
av_dump_format(ofmt_ctx, 0, filename, 1);
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
return ret;
}
}
/* init muxer, write output file header */
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
return ret;
}
return 0;
}
int main(int argc, char **argv)
{
int ret;
AVPacket packet = {0};
packet.data = NULL;
packet.size = 0 ;
AVFrame *frame = NULL;
enum AVMediaType type;
unsigned int stream_index;
unsigned int i;
int got_frame;
int(*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
if (argc != 3) {
av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file="file" /> <output file="file">\n", argv[0]);
return 1;
}
av_register_all();
avfilter_register_all();
if ((ret = open_input_file(argv[1])) < 0)
goto end;
if ((ret = open_output_file(argv[2])) < 0)
goto end;
/* read all packets */
while (1) {
if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0)
break;
stream_index = packet.stream_index;
type = ifmt_ctx->streams[packet.stream_index]->codecpar->codec_type;
av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n", stream_index);
/* remux this frame without reencoding */
av_packet_rescale_ts(&packet,
ifmt_ctx->streams[stream_index]->time_base,
ofmt_ctx->streams[stream_index]->time_base);
ret = av_interleaved_write_frame(ofmt_ctx, &packet);
if (ret < 0)
goto end;
av_packet_unref(&packet);
}
av_write_trailer(ofmt_ctx);
end:
av_packet_unref(&packet);
av_frame_free(&frame);
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
avcodec_free_context(&stream_ctx[i].dec_ctx);
if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && stream_ctx[i].enc_ctx)
avcodec_free_context(&stream_ctx[i].enc_ctx);
}
av_free(stream_ctx);
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return ret ? 1 : 0;
}
</output>This is a little bit changed code from official example of using ffmpeg called transcoding.c
I only read packets from one stream and write them to another stream. It works fine.
then I add to main a condition. If it is a packet with video frame, I will decode it, then encode and write to another stream. No other actions with frame.
My addition code below :
static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) {
int ret;
int got_frame_local;
AVPacket enc_pkt;
int(*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) = avcodec_encode_video2 ;
if (!got_frame)
got_frame = &got_frame_local;
av_log(NULL, AV_LOG_INFO, "Encoding frame\n");
/* encode filtered frame */
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt,
filt_frame, got_frame);
if (ret < 0)
return ret;
if (!(*got_frame))
return 0;
/* prepare packet for muxing */
enc_pkt.stream_index = stream_index;
av_packet_rescale_ts(&enc_pkt,
stream_ctx[stream_index].enc_ctx->time_base,
ofmt_ctx->streams[stream_index]->time_base);
av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
/* mux encoded frame */
ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
return ret;
}
static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
{
int ret;
av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n");
while (1) {
av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n");
ret = encode_write_frame(frame, stream_index, NULL);
if (ret < 0)
break;
break;
}
return ret;
}
int main(int argc, char **argv)
{
int ret;
AVPacket packet = {0};
packet.data = NULL;
packet.size = 0 ;
AVFrame *frame = NULL;
enum AVMediaType type;
unsigned int stream_index;
unsigned int i;
int got_frame;
int(*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
if (argc != 3) {
av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file="file" /> <output file="file">\n", argv[0]);
return 1;
}
av_register_all();
avfilter_register_all();
if ((ret = open_input_file(argv[1])) < 0)
goto end;
if ((ret = open_output_file(argv[2])) < 0)
goto end;
/* read all packets */
while (1) {
if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0)
break;
stream_index = packet.stream_index;
type = ifmt_ctx->streams[packet.stream_index]->codecpar->codec_type;
av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n",
stream_index);
if (type == AVMEDIA_TYPE_VIDEO)
{
av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n");
frame = av_frame_alloc();
if (!frame) {
ret = AVERROR(ENOMEM);
break;
}
av_packet_rescale_ts(&packet,
ifmt_ctx->streams[stream_index]->time_base,
stream_ctx[stream_index].dec_ctx->time_base);
dec_func = avcodec_decode_video2;
ret = dec_func(stream_ctx[stream_index].dec_ctx, frame,
&got_frame, &packet);
if (ret < 0) {
av_frame_free(&frame);
av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
break;
}
if (got_frame) {
frame->pts = frame->best_effort_timestamp;
ret = filter_encode_write_frame(frame, stream_index);
av_frame_free(&frame);
if (ret < 0)
goto end;
}
else {
av_frame_free(&frame);
}
}
else
{
/* remux this frame without reencoding */
av_packet_rescale_ts(&packet,
ifmt_ctx->streams[stream_index]->time_base,
ofmt_ctx->streams[stream_index]->time_base);
ret = av_interleaved_write_frame(ofmt_ctx, &packet);
if (ret < 0)
goto end;
}
av_packet_unref(&packet);
}
av_write_trailer(ofmt_ctx);
end:
av_packet_unref(&packet);
av_frame_free(&frame);
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
avcodec_free_context(&stream_ctx[i].dec_ctx);
if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && stream_ctx[i].enc_ctx)
avcodec_free_context(&stream_ctx[i].enc_ctx);
}
av_free(stream_ctx);
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return ret ? 1 : 0;
}
</output>And the result is different.
For a test I took a SampleVideo_1280x720_1mb.flv.
It hasFile size : 1.00 MiB
Overall bit rate : 1 630 kb/sAfter my decode/encode actions the result became :
File size : 1.23 MiB
Overall bit rate : 2 005 kb/sOther parameters (video bit rate, audio bit rate, etc) are the same.
What am I doing wrong ? How to control overall bit rate ? I suppose, something wrong with encoder/decoder, but what ?
UPD :
I get that when in functionopen_input_file
I writeif (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
{
codec_ctx->framerate = av_guess_frame_rate(ifmt_ctx, stream, NULL);
}I get what I get (bigger size and bit rate).
And when in this function I write
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
{
codec_ctx = ifmt_ctx->streams[i]->codec;
}I get smaller size and bit rate.
File size : 900 KiB
Overall bit rate : 1 429 kb/sBut how to get the exactly size and frame rate as in the original file ?