Función de transmisión en vivo de OSS para compartir en profundidad

Descripción de la escena

En la actualidad, muchos entusiastas de la transmisión en vivo usan la transmisión en vivo de transmisión en vivo hecha por OSS + RTMP, y hay muchas aplicaciones de nivel empresarial. Debido a que OSS como recepción de transmisión en vivo es un poco más complicado, se discutirá por separado. De hecho, no se recomienda usar OSS + RTMP para la transmisión en vivo, ya que la funcionalidad se compara con los productos de transmisión en vivo profesionales de Alibaba Cloud, la transmisión OSS es adecuada para escenarios específicos como la copia de seguridad supervisora, y el cliente no es muy sensible a los requisitos de retraso de la transmisión en vivo. Si tiene un escenario altamente sensible para retrasos de transmisión y extracción de transmisión en vivo, se recomienda que utilice el servicio de transmisión de video en vivo de Alibaba Cloud, que puede lograr la aceleración de enlace ascendente y descendente y admite la adaptación diversificada de la función de transmisión en vivo;

Usa lo básico

Conocimiento en vivo simple

Debe comprender o incluso dominar las habilidades simples de conocimiento de transmisión en vivo para poder utilizar la transmisión en vivo de OSS de manera competente, no solo para OSS sino también temas relacionados, como el impulso del cliente, por lo que debe comprender la base relevante de la transmisión en vivo

[Introducción de encabezados de audio y video]

La función de transmisión en vivo de OSS se basa en el protocolo de transmisión de transmisión en vivo RTMP, por lo que es necesario guiar algunos conocimientos básicos de RMTP: la forma de encapsulación de la transmisión de audio y video RTMP es similar al formato FLV, y el servidor de medios de transmisión envía RTMP incluyendo H264 y AAC al cliente Para la transmisión en vivo, estos dos encabezados deben enviarse primero. Sin esta información, el reproductor no puede decodificar las transmisiones de audio y video. El formato de la etiqueta de audio es el siguiente

1) Encabezado de secuencia AVC
2) El encabezado de secuencia AAC
imagen
deduce de lo anterior que los primeros 2 bytes del contenido del encabezado de secuencia AAC son 0xAF 0x00, veamos un ejemplo:
imagen

3) ADIF: Formato de intercambio de datos de audio. La característica de este formato es que el inicio de los datos de audio puede determinarse sin decodificación en el medio del flujo de datos de audio, es decir, su decodificación debe realizarse en un inicio claramente definido. Por lo tanto, este formato se usa comúnmente en archivos de disco.

4) ADTS: Transmisión de datos de audio. La característica de este formato es que es una secuencia de bits con palabras de sincronización, y la decodificación puede comenzar en cualquier parte de esta secuencia. Sus características son similares al formato de flujo de datos mp3.

[Introducción de contenido RTMP]

La siguiente es una descripción completa de mi resumen de RTMP

imagen

Arquitectura de flujo de inserción de almacenamiento de objetos

Mire la definición del sitio web oficial del proceso de flujo de inserción OSS:

1) RTMP solo se puede usar para impulsar la transmisión, y la transmisión de extracción no es compatible.
2) Se debe incluir la transmisión de video y el formato de transmisión de video es H264.
3) La transmisión de audio es opcional y solo admite el formato AAC; se descartarán otros formatos de transmisión de audio.
4) Dump solo admite el protocolo HLS.
5) Solo un cliente puede enviar una transmisión a un LiveChannel a la vez.

Formato de flujo de inserción RTMP:

  • demo : rtmp: //your-bucket.oss-cn-hangzhou.aliyuncs.com/live/test-channel
  • Live es equivalente al punto de montaje de la aplicación RTMP
  • test-channel es equivalente al nombre de flujo de RTMP

Firma de inserción de URL RTMP:

  • demo : rtmp: // $ {bucket}. $ {host} / live / $ {channel}? OSSAccessKeyId = xxx & Expires = aaa & Signature = zzz & $ {params}
  • Antes de transmitir, LiveChannel tiene dos estados: habilitado y deshabilitado. Los usuarios pueden usar esta interfaz para cambiar entre los dos estados. Cuando está en el estado deshabilitado, el OSS prohibirá a los usuarios enviar transmisiones al LiveChannel; si un usuario empuja transmisiones al LiveChannel, el cliente de transmisión se desconectará por la fuerza (puede demorarse unos 10 segundos)

El resumen del proceso del flujo de inserción de almacenamiento de objetos es el siguiente

Generar API de flujo de inserción API
establecer API de estado de flujo de inserción

imagen

Utilice el SDK de JAVA para generar URL de inserción

Ahora usamos el SDK de Java para demostrar el proceso de razonamiento anterior. Antes de ejecutar el SDK, necesitamos configurar un entorno de eclipse local. El siguiente es el eclipse que uso. Si no hay nadie, busque el método de construcción del eclipse en línea (antes Necesita instalar JDK y configurar variables de entorno)

Requisitos ambientales

  • Versión de Eclipse: Versión: Neon.3 Release (4.6.3)
  • Versión JDK: jdk1.8.0_144
  • OSS: lectura abierta (para verificar si la función de flujo de empuje es normal, probamos rápidamente con lectura abierta)
  • Utilizamos el método de entrada de la función principal para crear instancias de otras clases para llamar, lo cual es conveniente para la división de clases, no todas recopiladas en la función principal.
  • El dominio de la función principal, el objeto OSSClient instanciado se pasa a la clase RtmpTest para su prueba.
  • Todos los frascos se resolverán a través de las dependencias oficiales de Maven, https://help.aliyun.com/document_detail/32009.html
package javasdk;

import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

import com.aliyun.oss.OSSClient;

public class domain {
    public static void main( String[] args ) throws ParseException, FileNotFoundException
    {
        
        System.out.println( "Hello World!" );
        String accessid = "AK";
        String secretkey = "SK";
        String objectpath = "C://Users//hanli.zyb//Desktop//running.png";
        String bucket = "bucket";
        String object = "running";
        String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";

        
        // OSS + rtmp 推流
        String bucketName = "ali-hangzhou";
        RtmpTest pushoss = new RtmpTest();
        OSSClient ossClient = new OSSClient(endpoint, AK, SK);
        pushoss.testCreateLiveChannel(bucketName,ossClient);

    }
}
​```

/ *

  • Con licencia para Apache Software Foundation (ASF) bajo uno
  • o más acuerdos de licencia de contribuyente. Ver el archivo de AVISO
  • distribuido con este trabajo para información adicional
  • con respecto a la propiedad de los derechos de autor. La ASF licencia este archivo
  • a usted bajo la Licencia Apache, Versión 2.0 (la
  • "Licencia"); no puede usar este archivo excepto en cumplimiento
  • con la licencia Puede obtener una copia de la Licencia en
    *
  • http://www.apache.org/licenses/LICENSE-2.0
    *
  • A menos que lo exija la ley aplicable o se acuerde por escrito,
  • el software distribuido bajo la Licencia se distribuye en un
  • "TAL CUAL", SIN GARANTÍAS O CONDICIONES DE CUALQUIERA
  • TIPO, ya sea expreso o implícito. Ver la licencia para
  • Lenguaje específico que rige los permisos y limitaciones
  • bajo la licencia.
    * /

paquete javasdk;

import java.text.ParseException;
import java.util.Date;
import java.util.List;
import junit.framework.Assert;

import org.junit.Ignore;
import org.junit.Test;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSErrorCode;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateLiveChannelRequest;
import com.aliyun.oss.model.CreateLiveChannelResult;
import com.aliyun.oss.model.ListLiveChannelsRequest;
import com.aliyun.oss.model.LiveChannel;
importar com.aliyun.oss.model.LiveChannelInfo;
import com.aliyun.oss.model.LiveChannelListing;
import com.aliyun.oss.model.LiveChannelStat;
import com.aliyun.oss.model.LiveChannelStatus;
import com.aliyun.oss.model.LiveChannelTarget;
import com.aliyun.oss.model.LiveRecord;
importar com.aliyun.oss.model.PushflowStatus;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

/ **

  • Prueba rtmp
    * /

clase pública RtmpTest {

String bucketName = "bucket";
final String liveChannel = "stream name";
@Test
public void testCreateLiveChannelDefault(String bucketname,OSSClient ossClient) {

    try {
        CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                bucketName, liveChannel);
        CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
        LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel);

        
        ossClient.deleteLiveChannel(bucketName, liveChannel);
    } catch (Exception e) {
        Assert.fail(e.getMessage());
    }
}

@Test
public void testCreateLiveChannel(String bucketname,OSSClient ossClient) {
    final String liveChannel = "normal-create-live-channel";
    final String liveChannelDesc = "my test live channel";

    try {
        LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8");
        CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target);
        
        CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
        System.out.println(createLiveChannelResult.getPublishUrls());
        /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1);
        Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://"));
        Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel));
        Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1);
        Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://"));
        Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/
        
       /* LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel);
        Assert.assertEquals(liveChannelInfo.getDescription(), liveChannelDesc);
        Assert.assertEquals(liveChannelInfo.getStatus(), LiveChannelStatus.Disabled);
        Assert.assertEquals(liveChannelInfo.getTarget().getType(), "HLS");
        Assert.assertEquals(liveChannelInfo.getTarget().getFragDuration(), 100);
        Assert.assertEquals(liveChannelInfo.getTarget().getFragCount(), 99);
        Assert.assertEquals(liveChannelInfo.getTarget().getPlaylistName(), "myplaylist.m3u8");*/
        
        
       // ossClient.deleteLiveChannel(bucketName, liveChannel);
    } catch (Exception e) {
        Assert.fail(e.getMessage());
    }
}

}


其中我们最关注的是 testCreateLiveChannel 类,创建了推流地址,其中参数 LiveChannelStatus.enable 是要让推流变为可用状态。
running 主函数,打印出推流地址。
rtmp://hangzhou.oss-cn-hangzhou.aliyuncs.com/live/normal-create-live-channel

public void testCreateLiveChannel (Stringname, OSSClient ossClient) {

    final String liveChannel = "normal-create-live-channel";
    final String liveChannelDesc = "my test live channel";

    try {
        LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8");
        CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
                bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target);
        
        CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
        System.out.println(createLiveChannelResult.getPublishUrls());
        /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1);
        Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://"));
        Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel));
        Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1);
        Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://"));
        Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/
        
        
       // ossClient.deleteLiveChannel(bucketName, liveChannel);
    } catch (Exception e) {
        Assert.fail(e.getMessage());
    }
}​

Supongo que te gusta

Origin yq.aliyun.com/articles/754953
Recomendado
Clasificación