Cómo utilizar FFMPEG H264 para implementar la transmisión de datos RTP
WINDOWS7 32bit
MINGW
eclipse juno cdt
1. Primero, compila FFMPEG,
b) Método 2: el método que ahorra más trabajo es descargar recursos que han sido compilados por otros, como ZeranoeFFmpeg. Descargue su versión de desarrollo, que contiene archivos de encabezado, bibliotecas y otras cosas necesarias. Por supuesto, esto ya es compatible con H264.
2. La siguiente es la parte del código:
a) Primero declare las variables necesarias:
AVFormatContext *fmtctx
AVStream; *video_st ;
AVCodec *video_codec;
const int FPS = 25 /* 25 imágenes/s */
const char *RDIP = "127.0. 0.1" ;
unsigned int RDPORT = 5678;
const unsigned int OUTWIDTH = 720;
const unsigned int OUTHEIGHT = 480;
av_register_all ();
avformat_network_init();
b) Inicializar contenedor AV
fmtctx = avformat_alloc_context(); Obtenga el formato de salida, aquí está el flujo de red RTP
fmtctx-gt; offormat = av_guess_format("rtp", NULL, NULL);
d) Abra el flujo de red
snprintf(fmtctx-gt; nombre de archivo, tamaño de(fmtctx-gt; nombre de archivo), "rtp://s:d", RDIP, RDPORT);
avio_open(amp; fmtctx-gt ; pb, fmtctx-gt; nombre de archivo, AVIO_FLAG_WRITE)
e) Comience a agregar transmisión de video H264
video_st = NULL;
La función add_video_stream está aquí:
add_video_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec _id)
{
AVCodecContext *c ;
AVStream *st;
/* Buscar codificador de vídeo*/
*codec = avcodec_find_encoder(codec_id); p>st = avformat_new_stream(oc, *codec);
c = st-gt;codec;
avcodec_get_context_defaults3(c, *codec);
c -gt; codec_ id = codec_id;
c-gt; ancho = OUTWIDTH;
c-gt; alto = OUTHEIGHT
c-gt; .den = FPS;
c-gt; tiempo_base.num = 1;
c-gt; pix_fmt = PIX_FMT_YUV420P; offormat-gt; bandera
s amp; AVFMT_GLOBALHEADER)
c-gt;flags|= CODEC_FLAG_GLOBAL_HEADER;
av_opt_set(c-gt;priv_data, "preset", "ultrafast", 0);
p>av_opt_set(c-gt;priv_data, "tune", "stillimage, fastdecode, zerolatency", 0);
av_opt_set(c-gt;priv_data, "x264opts", "crf = 26: vbv-maxrate=728: vbv-bufsize=364: keyint=25", 0); return st; }
//Código abierto
avcodec_open2(video_st-gt ; codec, video_codec, NULL);
/* Escribe el encabezado de la transmisión (si lo hay). */ )
{
fill_yuv_image(m_pYUVFrame, video_st-gt; codec-gt; frame_number, OUTWIDTH, OUTHEIGHT);
/*imagen codificada*/
AVPacket pkt;
int got_output = 0;
av_init_packet(amp;pkt);
pkt.data = NULL; / Los datos del paquete serán asignados por el codificador
pkt.dts = AV_NOPTS_VALUE;
m_ pYUVFrame-gt; pts = video_st-gt; frame_number;
ret = avcodec_encode_video2(c,amp;pkt,frame,amp;got_output);
if (ret lt;0) {fprintf(stderr, "Error al codificar fotograma de vídeo: s\n", av_err2str (ret));
exit(1);
}
/* Si el tamaño es cero, la imagen se almacena en el buffer.
*/
if (got_output)
{
if (c-gt;coded_frame-gt;key_frame)pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index=st-gt;index;
if (pkt.pts ! = AV_NOPTS_VALUE )
{
pkt.pts = av_rescale_q (pkt.pts, video_st-gt; codec-gt; time_base, video_st-gt; time_base);
}
if (pkt.dts ! =AV_NOPTS_VALUE )
{
pkt.dts = av_rescale_q(pkt.dts, video_st-gt; codec-gt; time_base, video_st-gt; time_base;
}<); /p>
Escribe el archivo comprimido en el compilador. */
ret = av_interleaved_write_frame(oc, amp; pkt
}
else {
ret = 0; p>
p>
}
}
g) Función Fill_yuv_image:
//* Preparar una imagen virtual.
*/
static void fill_yuv_image(AVPicture *pict, int frame_ index, int width, int height)
{
int x, y, i;
i = frame_index;
/* Y */
para (y = 0; y lt; altura; y)
para (x = 0; x lt; ancho; x)
pict-gt; datos[0][y * pict-gt; tamaño de línea[0] x] = x y i * 3;
/* Cb y Cr */
para (y = 0; y lt; altura / 2; y)
{
para (x = 0; x lt; ancho / 2; * 2;
pict-gt;datos[2][y * pict-gt;tamaño de línea[2] x] = 64 x i * 5;
}
}
}
}
h) Imprimir información sdp, solo una vez La información sdp impresa se utiliza. en el reproductor VLC para finalizar la transmisión de vídeo en red
//Imprimir información sdp
char sdp[2048];
av_sdp_create(amp; fmtctx, 1, sdp , sizeof(sdp));
printf("s\n", sdp);
fflush(stdout);
i)Finalmente, haz algo trabajo de limpieza <
avcodec_free_frame(amp; m_pYUVFrame
av_write_trailer(fmtctx
/* Libera las transmisiones.*/
for (unsigned int i = 0; i lt; fmtctx-gt; nb_streams; i )
{
av_freep(amp; fmtctx-gt; streams-gt; codec);
av_freep(amp ; fmtctx-gt; transmisiones);
}
if(! (fmtctx-gt; offormat-gt; flagsamp; AVFMT_NOFILE))
/* Cierra el archivo de salida.
avio_close(fmtctx-gt;pb);
/*libera la transmisión*/
av_free(fmtctx);
3 , Compile el código, recuerde agregar el archivo de la biblioteca, ejecute el código una vez, no haga un bucle interminable, no configure ningún bucle, porque esto es para permitirle imprimir la información del archivo sdp.
Obtenga información de sdp, por ejemplo, la condensé de la siguiente manera:
c=IN IP4 127.0.0.1
m=video 56782 RTP/AVP 96
a =rtpmap: 96 H264/90000
a=framerate:25
a=fmtp:96 paquetes-mode=1
Guarde esta información en un archivo de texto y repita Nómbrelo con el sufijo sdp, como mySDP.sdp.
4. Descargue el reproductor VLC del sitio web oficial y vuelva a ejecutar el código anterior. Esta vez desea realizar el bucle. Lo que quieras hacer depende de ti. Esta vez es una prueba oficial. Después de ejecutar el código, use VLC para abrir el archivo sdp ahora y simplemente arrastre el archivo sdp directamente al reproductor VLC. Espere a que se almacene en búfer para ver los resultados.
5. Falta la parte de verificación de errores en el código, agréguela usted mismo.
6. En cuanto a la dirección IP, aquí está 127.0.0.1, que se utiliza para pruebas locales. Se puede cambiar a la dirección IP de la computadora de desarrollo que recibe los datos o a la dirección IP de la transmisión. DIRECCIÓN.