awslabs / amazon-kinesis-video-streams-producer-sdk-java

Allows developers to install and customize their connected camera and other devices to securely stream video, audio, and time-encoded data to Kinesis Video Streams
Apache License 2.0
78 stars 77 forks source link

Invalid mkv data, converting the file with ffmpeg #41

Closed roccomuso closed 4 years ago

roccomuso commented 6 years ago

I'm using this:

ffmpeg -i rtsp://admin:@192.168.1.10:554/live1.sdp -b:v 10M -minrate 10M -maxrate 10M -bufsize 10M -bf 0 input.mkv

That i found here /demoapp/PutMediaDemo.java#L41

But after a couple of fragments successfully RECEIVED, i get this error:

{"EventType":"ERROR","FragmentTimecode":160,"FragmentNumber":"91343852333181481954849475441990835530935416709","ErrorCode":"INVALID_MKV_DATA","ErrorId":4006}
roccomuso commented 6 years ago

It seems that the error is raised when I put some data chunk that has no signature. How do I provide a payload stream without having to sign it?

PS. another question, is this a valid ffmpeg format to be able to see the mkv video on the video preview dashboard window?

ffmpeg -re -i rtsp://admin:@192.168.1.10:554/live1.sdp -b:v 1000k -vcodec copy -f matroska -map 0:0 -timestamp now pipe:1

MushMal commented 6 years ago

@roccomuso thanks for reaching out. MKV (Matroska) which is our packaging layer can have a very diverse format. Kinesis Video Service supports a small subset of it. Generally speaking, our payload of MKV is transport-layer security protected (TLS). The error you are seeing indicates that there the backend parser detected something that it doesn't understand.

Can I ask you a more general question... What are you trying to accomplish? If you are trying to simply stream RTSP stream then why don't you try the RTSP sample app we provided?

https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp#2-gstreamer-rtsp-demo-application

roccomuso commented 6 years ago

Thanks for the reply. I'm trying to do it in JS with ffmpeg.

That cpp sdk and container are too big for my purpose.

I was able to do it in JS, but now i'm facing 2 different issues. 1) I'm not sure if the mkv i'm sending is considered valid since i can't see it on the video preview page. 2) In the cloudwatch metrics i can't see accepted fragments or IncomingBytes.

But I do have responses like that:

{"EventType":"BUFFERING","FragmentTimecode":10300,"FragmentNumber":"91343852333183806662642208829064498921044452687"}
{"EventType":"PERSISTED","FragmentTimecode":2467,"FragmentNumber":"91343852333183806657690448671922976710400120202"}
{"EventType":"RECEIVED","FragmentTimecode":10300,"FragmentNumber":"91343852333183806662642208829064498921044452687"}

I'm using a relative timecode-type and this is the date string format i'm sending (is it right?):

   "x-amzn-fragment-timecode-type": "RELATIVE",
   "x-amzn-producer-start-timestamp": "Fri, 22 Jun 2018 13:12:27 GMT",
dagsonpatrick commented 5 years ago

Hi @roccomuso

I'm trying to send stream video via rtsp camera in Java.

Would you help me.

Where I put this snippet of code

ffmpeg -i rtsp://admin:@192.168.1.10:554/live1.sdp -b:v 10M -minrate 10M -maxrate 10M -bufsize 10M -bf 0 input.mkv

Código: `public final class PutMediaDemo {

private static final String DEFAULT_REGION = "us-west-2";
private static final String PUT_MEDIA_API = "rtsp://192.168.10.252:554/axis-media/media.amp?videocodec=h264";   
/* the name of the stream */
private static final String STREAM_NAME = "camera";//my-stream

/* sample MKV file */
private static final String MKV_FILE_PATH = "src/main/resources/data/mkv/clusters.mkv";

/* max upload bandwidth */
private static final long MAX_BANDWIDTH_KBPS = 15 * 1024L;

/* response read timeout */
private static final int READ_TIMEOUT_IN_MILLIS = 1_000_000;

/* connect timeout */
private static final int CONNECTION_TIMEOUT_IN_MILLIS = 10_000;

static InputStreamReader in = null;
static FFmpegFrameGrabber cameraIP;

private PutMediaDemo() { }

public static void main(final String[] args) throws Exception {

    cameraIP = new FFmpegFrameGrabber("rtsp://192.168.10.252:554/axis-media/media.amp?videocodec=h264");

    final AmazonKinesisVideo frontendClient = AmazonKinesisVideoAsyncClient.builder()
            .withCredentials(AuthHelper.getSystemPropertiesCredentialsProvider())
            .withRegion(DEFAULT_REGION)
            .build();

    /* this is the endpoint returned by GetDataEndpoint API */
    final String dataEndpoint = frontendClient.getDataEndpoint(
            new GetDataEndpointRequest()  
                    .withStreamName(STREAM_NAME)
                    .withAPIName("PUT_MEDIA")).getDataEndpoint();

    cameraIP.start();

    Java2DFrameConverter converte = new Java2DFrameConverter();
    /* send the same MKV file over and over */

    while (true) {

        /* actually URI to send PutMedia request */
        final URI uri = URI.create(dataEndpoint + PUT_MEDIA_API);

         Frame frame = cameraIP.grabFrame();

         BufferedImage buff = converte.convert(frame);

         byte[] buffer = ((DataBufferByte)buff.getRaster().getDataBuffer()).getData();

        /* input stream for sample MKV file */
        final InputStream inputStream = new ByteArrayInputStream(buffer);

        /* use a latch for main thread to wait for response to complete */
        final CountDownLatch latch = new CountDownLatch(1);

        /* PutMedia client */
        final AmazonKinesisVideoPutMedia dataClient = AmazonKinesisVideoPutMediaClient.builder()
                .withRegion(DEFAULT_REGION)
                .withEndpoint(URI.create(dataEndpoint))
                .withCredentials(AuthHelper.getSystemPropertiesCredentialsProvider())
                .withConnectionTimeoutInMillis(CONNECTION_TIMEOUT_IN_MILLIS)
                .build();

        final PutMediaAckResponseHandler responseHandler = new PutMediaAckResponseHandler()  {
            @Override
            public void onAckEvent(AckEvent event) {
                System.out.println("onAckEvent " + event);
            }

            @Override
            public void onFailure(Throwable t) {
                latch.countDown();
                System.out.println("onFailure: " + t.getMessage());
                // TODO: Add your failure handling logic here
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
                latch.countDown();
            }
        };

        /* start streaming video in a background thread */
        dataClient.putMedia(new PutMediaRequest()
                        .withStreamName(STREAM_NAME)
                        .withFragmentTimecodeType(FragmentTimecodeType.RELATIVE)
                        .withPayload(inputStream)
                        .withProducerStartTimestamp(Date.from(Instant.now())),
                responseHandler);

        /* wait for request/response to complete */
        latch.await();

        /* close the client */
        dataClient.close();

    }
}

}`

zhiyua-git commented 5 years ago

Hi @dagsonpatrick ,

One thing I noticed is the PUT_MEDIA_API you provided in Uri is incorrect.

_final URI uri = URI.create(dataEndpoint + PUT_MEDIA_API);_

_private static final String PUT_MEDIA_API = "rtsp://192.168.10.252:554/axis-media/media.amp?videocodec=h264";_

Also the input of one PutMedia call need to be a complete mkv file, I suspect cameraIP.grabFrame() would not give you complete mkv file every time. It might cause issue too.

Hope it helps. -ZH

dagsonpatrick commented 5 years ago

Hi @zhiyua-git ,

Thanks a lot for the help.

Unfortunately, even with these fixes, it was not possible to solve my need.

I need to send Stream RTSP from an IP camera to Kinesis, via Java application.

At AWS I found no demonstration example in this regard, via Java application.

If you have another solution to send Stream RTSP from an IP camera to Kinesis, I'm grateful.

hugs!

poojakittur commented 5 years ago

Hi,

I am trying to stream a .mp4 file which is converted to .mkv format using ffmpeg command to kinesis using PutMediaDemo class. The kinesis video streaming console is showing the error shown below:

Exception: InvalidCodecPrivateDataException Status code: 400 Request ID: f59142cd-22a6-4e08-ba5b-417de030ba96

I am using command given below to convert mp4 to mkv: ffmpeg -i input.mp4 -b:v 10M -minrate 10M -maxrate 10M -bufsize 10M -bf 0 input.mkv

Here are the on my local server: onAckEvent AckEvent{ackEventType=PERSISTED, fragmentTimecode=158498, fragmentNumber='91343852333181615800926522983015284194795592259', errorCode=null, errorId=null} onAckEvent AckEvent{ackEventType=PERSISTED, fragmentTimecode=163490, fragmentNumber='91343852333181615805878283140156805376024987217', errorCode=null, errorId=null} onAckEvent AckEvent{ackEventType=RECEIVED, fragmentTimecode=166835, fragmentNumber='91343852333181615810830043297298326488950635479', errorCode=null, errorId=null}

Could you please help me understand what am I doing wrong?

MushMal commented 5 years ago

@roccomuso @poojakittur - sorry this didn't work. It seems that your stream was being ingested just fine but due to the CPD (Codec Private Data) either being invalid or in a wrong format - the console will use AvCC format instead of Annex-B. I can't seem to find any documentation for ffmpeg on how to output AvCC format for both the CPD as well as the frames but this is what's required for the playback on the console.

@dagsonpatrick it seems that Netty (https://netty.io/) provides some support in Java for RTSP streams. See if you can use that.

poojakittur commented 5 years ago

Thank you so much @MushMal for the help.

Could you please help me with the ffmpeg command to convert mp4 to mkv such that CPD will be in correct format.

MushMal commented 5 years ago

@poojakittur will be glad to look into it but as is, I don't see anything in the public documentation.

poojakittur commented 5 years ago

@MushMal So does that mean, at present we can not stream a .mp4 file to kinesis?

MushMal commented 5 years ago

@poojakittur one can think of streaming .mp4 as a complex media pipeline. The KVS itself doesn't ingest .mp4 as it's a complex packaging format that is inherently non-streamable in nature.

Presently, it's possible to use code that can unpackage the .mp4, select the right media, stream using KVS producer assets. For example, the file uploader application in the CPP SDK does that.

The difficulty in using ffmpeg is that we have no native plugin for it that handles the streaming unlike GStreamer pipeline.

The Service-side API itself ingests sub-set of MKV. What you are trying to achieve is to get ffmpeg to generate a special type of MKV which 1) can be streamed to KVS and 2) Can be displayed in the KVS console which has special requirements of the stream being h264 and both the CPD (Codec Private Data) and the frames be in AcCC NALu format and not Annex-B or raw. This restriction comes from the browsers support of MSE.

I will update the thread if I find more useful information about ffmpeg integration.

poojakittur commented 5 years ago

Thank you so much @MushMal for the explanation.

vijaygj commented 5 years ago

I am trying to stream a .mp4 file which is converted to .mkv format using ffmpeg command to kinesis using PutMediaDemo class. The kinesis video streaming console is showing the error shown below:

Can you please confirm what is your use case here? You can use Android or Producer SDK to capture video directly and might be easier route.

poojakittur commented 5 years ago

Hi @vijaygj,

I am using Java producer library to stream .mp4 file to kinesis. Before streaming I am converting .mp4 file .mkv format using ffmpeg.

vijaygj commented 5 years ago

I was curious about how the MP4 file is generated in the first place. Anyway, kinesis video has published examples using gstreamer for camera or using rtsp steam.

https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/install-instructions-linux.md#running-the-gst-launch-10-command-to-start-streaming-both-audio-and-video-in-raspberry-pi-and-ubuntu

So gstreamer might be easier for you,

https://stackoverflow.com/questions/30190321/how-to-convert-mp4-to-mkv-h-264-with-gst-launch-1-0-on-raspberry-pi

On Fri, Feb 22, 2019 at 8:03 PM Pooja Kittur notifications@github.com wrote:

Hi @vijaygj https://github.com/vijaygj,

I am using Java producer library to stream .mp4 file to kinesis. Before streaming I am converting .mp4 file .mkv format using ffmpeg.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-java/issues/41#issuecomment-466614039, or mute the thread https://github.com/notifications/unsubscribe-auth/ABBSHfh8DnDFEnRNydVVDI66Cn32Tzr4ks5vQL2KgaJpZM4UyPaM .

poojakittur commented 5 years ago

Hi @vijaygj , @MushMal , Is there a way by which we can stream a video(.mp4 file) stored at S3 to kinesis using gstreamer?

zhiyua-git commented 5 years ago

Hi @poojakittur ,

You can download the mp4 and stream it to kinesis video with the gst-launch command here: https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/install-instructions-macos.md#running-the-gst-launch-10-command-to-upload-mp4-file-that-contains-both-audio-and-video-in-mac-os

poojakittur commented 5 years ago

Hi @zhiyua-git,

Thank you for the help. But is it possible to stream directly from S3 without downloading it? Can kinesis fetch stream from S3?

zhiyua-git commented 5 years ago

Hi @poojakittur , We don't fetch the stream directly into KVS now. You might be able to stream that to KVS via gstreamer plugin s3src. Please check the gstreamer document for the S3 support.

MushMal commented 4 years ago

Resolving this issue. The ingestion from S3 is certainly a path we are looking at. No timeline when we will implement it though.