peso para instalar guia especificar editar convertir comprimir como codecs ffmpeg encoder

para - ¿Cómo escribir un codificador de video con ffmpeg que controla explícitamente la posición de los fotogramas clave?



instalar codecs ffmpeg (6)

Quiero escribir un codificador con ffmpeg que pueda colocar iFrames (fotogramas clave) en las posiciones que desee. ¿Dónde puedo encontrar tutoriales o material de referencia para ello?

PD
¿Es posible hacer esto con mencoder o cualquier codificador de código abierto? Quiero codificar el archivo H263. Estoy escribiendo bajo y para linux.


Deberá consultar la documentación de libavcodec, específicamente, en avcodec_encode_video (). Descubrí que la mejor documentación disponible se encuentra en los archivos de cabecera ffmpeg y el código fuente de ejemplo de API que se proporciona con la fuente ffmpeg. Específicamente, mire libavcodec / api-example.c o incluso ffmpeg.c.

Para forzar un marco I, deberá configurar el miembro pict_type de la imagen que está codificando en 1: 1 es un marco I, 2 es un marco P, y no recuerdo cuál es el código para un marco B fuera de mi cabeza ... Además, el miembro key_frame debe configurarse en 1.

Hay algo de material de introducción disponible here y here , pero realmente no sé qué tan bueno es.

Deberá tener cuidado al asignar los objetos de marco que requieren las llamadas a la API. api-example.c es su mejor apuesta en lo que va, en mi opinión. Busque la función video_encode_example (): es concisa e ilustra todas las cosas importantes de las que debe preocuparse. Preste especial atención a la segunda llamada a avcodec_encode_video () que pasa un argumento de imagen NULA. Es necesario para obtener los últimos cuadros de video desde El video MPEG está codificado fuera de secuencia y puede terminar con un retraso de unos pocos cuadros.


Puede encontrar una versión actualizada de api-example.c en http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html

Realiza toda la codificación de video en una función única y relativamente corta. Así que este es probablemente un buen lugar para comenzar. Compilar y ejecutarlo. Y luego empieza a modificarlo hasta que haga lo que quieras.

También tiene codificación de audio y ejemplos de decodificación de audio y video.


Si eres programador de Java entonces usa Xuggler.


necesitará la biblioteca libavcodec. Para el primer paso, creo que puede aprender sobre su uso en el archivo ffplay.c dentro del código fuente de ffmpeg. Te diría mucho. También puede consultar mi proyecto sobre el video en rtstegvideo.sourceforge.net.

Espero que esto ayude.



Ejemplo ejecutable mínimo en FFmpeg 2.7

Basado en la respuesta de Ori Pessach , a continuación se muestra un ejemplo mínimo que genera marcos de forma.

  • yo
  • PAG
  • segundo
  • PAG
  • ...

Las partes clave del código que controlan el tipo de trama son:

c = avcodec_alloc_context3(codec); /* Minimal distance of I-frames. This is the maximum value allowed, or else we get a warning at runtime. */ c->keyint_min = 600; /* Or else it defaults to 0 b-frames are not allowed. */ c->max_b_frames = 1;

y:

frame->key_frame = 0; switch (frame->pts % 4) { case 0: frame->key_frame = 1; frame->pict_type = AV_PICTURE_TYPE_I; break; case 1: case 3: frame->pict_type = AV_PICTURE_TYPE_P; break; case 2: frame->pict_type = AV_PICTURE_TYPE_B; break; }

Luego podemos verificar el tipo de marco con:

ffprobe -select_streams v / -show_frames / -show_entries frame=pict_type / -of csv / tmp.h264

Como se mencionó en: https://superuser.com/questions/885452/extracting-the-index-of-key-frames-from-a-video-using-ffmpeg

FFmpeg impuso algunas reglas incluso si trato de superarlas:

  • El primer cuadro es un cuadro I
  • no se puede colocar un fotograma B0 antes de un fotograma I (TODO ¿por qué?)

Vista previa de la salida generada .

#include <libavcodec/avcodec.h> #include <libavutil/imgutils.h> #include <libavutil/opt.h> #include <libswscale/swscale.h> static AVCodecContext *c = NULL; static AVFrame *frame; static AVPacket pkt; static FILE *file; struct SwsContext *sws_context = NULL; /* Convert RGB24 array to YUV. Save directly to the `frame`, modifying its `data` and `linesize` fields */ static void ffmpeg_encoder_set_frame_yuv_from_rgb(uint8_t *rgb) { const int in_linesize[1] = { 3 * c->width }; sws_context = sws_getCachedContext(sws_context, c->width, c->height, AV_PIX_FMT_RGB24, c->width, c->height, AV_PIX_FMT_YUV420P, 0, 0, 0, 0); sws_scale(sws_context, (const uint8_t * const *)&rgb, in_linesize, 0, c->height, frame->data, frame->linesize); } /* Generate 2 different images with four colored rectangles, each 25 frames long: Image 1: black | red ------+----- green | blue Image 2: yellow | red -------+----- green | white */ uint8_t* generate_rgb(int width, int height, int pts, uint8_t *rgb) { int x, y, cur; rgb = realloc(rgb, 3 * sizeof(uint8_t) * height * width); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { cur = 3 * (y * width + x); rgb[cur + 0] = 0; rgb[cur + 1] = 0; rgb[cur + 2] = 0; if ((frame->pts / 25) % 2 == 0) { if (y < height / 2) { if (x < width / 2) { /* Black. */ } else { rgb[cur + 0] = 255; } } else { if (x < width / 2) { rgb[cur + 1] = 255; } else { rgb[cur + 2] = 255; } } } else { if (y < height / 2) { rgb[cur + 0] = 255; if (x < width / 2) { rgb[cur + 1] = 255; } else { rgb[cur + 2] = 255; } } else { if (x < width / 2) { rgb[cur + 1] = 255; rgb[cur + 2] = 255; } else { rgb[cur + 0] = 255; rgb[cur + 1] = 255; rgb[cur + 2] = 255; } } } } } return rgb; } /* Allocate resources and write header data to the output file. */ void ffmpeg_encoder_start(const char *filename, int codec_id, int fps, int width, int height) { AVCodec *codec; int ret; codec = avcodec_find_encoder(codec_id); if (!codec) { fprintf(stderr, "Codec not found/n"); exit(1); } c = avcodec_alloc_context3(codec); if (!c) { fprintf(stderr, "Could not allocate video codec context/n"); exit(1); } c->bit_rate = 400000; c->width = width; c->height = height; c->time_base.num = 1; c->time_base.den = fps; /* I, P, B frame placement parameters. */ c->gop_size = 600; c->max_b_frames = 1; c->keyint_min = 600; c->pix_fmt = AV_PIX_FMT_YUV420P; if (codec_id == AV_CODEC_ID_H264) av_opt_set(c->priv_data, "preset", "slow", 0); if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec/n"); exit(1); } file = fopen(filename, "wb"); if (!file) { fprintf(stderr, "Could not open %s/n", filename); exit(1); } frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Could not allocate video frame/n"); exit(1); } frame->format = c->pix_fmt; frame->width = c->width; frame->height = c->height; ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32); if (ret < 0) { fprintf(stderr, "Could not allocate raw picture buffer/n"); exit(1); } } /* Write trailing data to the output file and free resources allocated by ffmpeg_encoder_start. */ void ffmpeg_encoder_finish(void) { uint8_t endcode[] = { 0, 0, 1, 0xb7 }; int got_output, ret; do { fflush(stdout); ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame/n"); exit(1); } if (got_output) { fwrite(pkt.data, 1, pkt.size, file); av_packet_unref(&pkt); } } while (got_output); fwrite(endcode, 1, sizeof(endcode), file); fclose(file); avcodec_close(c); av_free(c); av_freep(&frame->data[0]); av_frame_free(&frame); } /* Encode one frame from an RGB24 input and save it to the output file. Must be called after ffmpeg_encoder_start, and ffmpeg_encoder_finish must be called after the last call to this function. */ void ffmpeg_encoder_encode_frame(uint8_t *rgb) { int ret, got_output; ffmpeg_encoder_set_frame_yuv_from_rgb(rgb); av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; switch (frame->pts % 4) { case 0: frame->key_frame = 1; frame->pict_type = AV_PICTURE_TYPE_I; break; case 1: case 3: frame->key_frame = 0; frame->pict_type = AV_PICTURE_TYPE_P; break; case 2: frame->key_frame = 0; frame->pict_type = AV_PICTURE_TYPE_B; break; } ret = avcodec_encode_video2(c, &pkt, frame, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame/n"); exit(1); } if (got_output) { fwrite(pkt.data, 1, pkt.size, file); av_packet_unref(&pkt); } } /* Represents the main loop of an application which generates one frame per loop. */ static void encode_example(const char *filename, int codec_id) { int pts; int width = 320; int height = 240; uint8_t *rgb = NULL; ffmpeg_encoder_start(filename, codec_id, 25, width, height); for (pts = 0; pts < 100; pts++) { frame->pts = pts; rgb = generate_rgb(width, height, pts, rgb); ffmpeg_encoder_encode_frame(rgb); } ffmpeg_encoder_finish(); } int main(void) { avcodec_register_all(); encode_example("tmp.h264", AV_CODEC_ID_H264); encode_example("tmp.mpg", AV_CODEC_ID_MPEG1VIDEO); /* TODO: is this encoded correctly? Possible to view it without container? */ /*encode_example("tmp.vp8", AV_CODEC_ID_VP8);*/ return 0; }

Probado en Ubuntu 15.10. GitHub aguas arriba .

¿ Realmente quieres hacer esto?

En la mayoría de los casos, es mejor controlar los parámetros globales de AVCodecContext .

FFmpeg hace cosas inteligentes como usar un fotograma clave si el nuevo marco es completamente diferente del anterior, y no se obtendría mucho de la codificación diferencial.

Por ejemplo, si configuramos solo:

c->keyint_min = 600;

luego obtenemos exactamente 4 fotogramas clave en el ejemplo anterior, lo cual es lógico ya que hay 4 cambios bruscos de fotogramas en el video generado.