livepeer / catalyst

Livepeer's Decentralized Media Server
MIT License
22 stars 14 forks source link

Change output video URL from *.ipfs.w3s.link to ipfs:// #397

Closed leszko closed 1 year ago

leszko commented 1 year ago

The videoFilePath should include an ipfs://<CID> instead of the complete web3.storage link to the manifest playback.

"output": {
    "transcodeFile": {
        "videoFilePath": "ipfs://bafybeibn34yirlf5mv4xvaouty7gveyc6hvsgkbq6nornzr4w53r7frgvq"
    }
}

The open question is how we want to approach different profiles and mp4 files. Currently, we include them only in the catalyst output, but not in the studio output. But maybe, in the future, we'll want to include them as well. Should we then add the relative paths to ipfs links, like ipfs://<CID>/path/to/mp4 (knowing that it's not a standard thing)? @yondonfu wdyt?

Here's an example of how it could look like:

"output": {
    "videos": [
    {
      "type": "hls",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e"
    },
    {
      "type": "hls_profile",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/1080p0/index.m3u8"
    },
    {
      "type": "hls_profile",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/720p0/index.m3u8"
    },
    {
      "type": "hls_profile",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/360p0/index.m3u8"
    },
    {
      "type": "hls_profile",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/360p0/index.m3u8"
    },
    {
      "type": "mp4",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/static360p0.mp4"
    },
    {
      "type": "mp4",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/static720p0.mp4
    },
    {
      "type": "mp4",
      "videoFilePath": "ipfs://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e/video/hls/static1080p0.mp4"
    },
    ]
}

Or maybe we should have another property for each output, like path? Or maybe don't include them, the user will need to figure them out.


For the context, here's what we currently return.

Studio

"output": {
    "transcodeFile": {
        "videoFilePath": "https://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e.ipfs.w3s.link/video/hls/index.m3u8"
    }
}

Catalyst (Mist)

"outputs": [
    {
      "type": "object_store",
      "manifest": "https://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e.ipfs.w3s.link/video/hls/index.m3u8",
      "videos": [
        {
          "type": "",
          "size": 4729892,
          "location": "https://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e.ipfs.w3s.link/video/hls/1080p0/index.m3u8"
        },
        {
          "type": "",
          "size": 3849112,
          "location": "https://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e.ipfs.w3s.link/video/hls/720p0/index.m3u8"
        },
        {
          "type": "",
          "size": 1187220,
          "location": "https://bafybeid5qqzthuy44y6vzmja7s4podwpgqqocrjq4nzeyatlqaldrwuh3e.ipfs.w3s.link/video/hls/360p0/index.m3u8"
        }
      ]
    }
  ]

Catalyst (Mediaconvert)

"outputs": [
    {
      "type": "object_store",
      "manifest": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/index.m3u8",
      "videos": [
        {
          "type": "m3u8",
          "size": 145,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/index360p0.m3u8"
        },
        {
          "type": "m3u8",
          "size": 145,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/index720p0.m3u8"
        },
        {
          "type": "m3u8",
          "size": 146,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/index1080p0.m3u8"
        }
      ]
    },
    {
      "type": "object_store",
      "videos": [
        {
          "type": "mp4",
          "size": 620321,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/static360p0.mp4"
        },
        {
          "type": "mp4",
          "size": 1700941,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/static720p0.mp4"
        },
        {
          "type": "mp4",
          "size": 3747307,
          "location": "https://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy.ipfs.w3s.link/video/hls/static1080p0.mp4"
        }
      ]
    }
  ]
yondonfu commented 1 year ago

I think we can learn from the recent update to the /playbackInfo endpoint in Studio described here to return multiple formats in a response i.e. a HLS URL and multiple mp4 URLs.

In this case, if/when we add support for mp4 output in the transcode API then the outputs object in a task response would look something like:

"hls": {
     // The path specified in the request
    "path": ...
     // Only for IPFS
    "url": ...
},
"mp4: {
     // The path specified in the request
    "path": ...
     // Only for IPFS
    "renditions": [
        { "url": ... },
        { "url": ... }
    ]
}

Tagging @victorges and @gioelecerati for feedback here as well.

leszko commented 1 year ago

Returning all video paths make sense, but I'm not sure I understand the output you presented. In particular why we would have multiple url entries in the mp4 output.

Let's maybe see how it will look like in two cases we have Storj and web3.storage.

Storj

A user sends the following request:

{
    "input": {
        "url": "https://storage.googleapis.com/thom-vod-testing/mustwork/Pexels%20Videos%203444.mp4"
    },
    "storage": {
        "type": "s3",
        "endpoint": "https://gateway.storjshare.io",
        "credentials": {
            "accessKeyId": "USER",
            "secretAccessKey": "PASS"
        },
        "bucket": "bucket"
    },
    "outputs": {
        "hls": {
            "path": "/video"
        }
    }
}

Then, the task output could look like this one:

"output": {
    "transcodeFile": {
        "hls": { 
            "path": "video/index.m3u8"
        },
        "mp4": {
            "renditions": [
                 { "path": "video/static360p0.mp4" },
                 { "path": "video/static720p0.mp4" },
                 { "path": "video/static1440p0.mp4" }
             ]         
        }
    }
}

We may consider adding index.m3u8 for profiles as well, like:

    "path": "video/index360p0.m3u8"   

web3.storage

"output": {
    "transcodeFile": {
        "url": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy",
        "hls": {
            "path": "video/index.m3u8"   
        },
        "mp4": {
            "renditions": [
                 { "path": "video/static360p0.mp4" },
                 { "path": "video/static720p0.mp4" },
                 { "path": "video/static1440p0.mp4" }
             ]         
        }
    }
}

We can consider nesting url inside hls and mp4, but it will always be the same url.

yondonfu commented 1 year ago

@leszko I think your examples make sense.

I originally included urls in each of the renditions for mp4 to account for a scenario where all the rendition files are not nested under the same directory. But, just going with the assumption that everything is nested under the same directory for now seems reasonable.

victorges commented 1 year ago

I like the last format you proposed @leszko!

We may consider adding index.m3u8 for profiles as well, like:

For the "upload API" I think we don't want that, as it feels like an implementation detail for a user that just want a simple upload + optimized playback for their files. It could make sense on the transcode API tho as I see it as a lower-level building block for more technical users, so it could be useful as well. We could probably wait for some user to need this before adding it though, just to avoid possibly bloating the interface.

like ipfs:///path/to/mp4 (knowing that it's not a standard thing)

I actually liked that format too, and it is what I was going to suggest before reading that. I was not aware that it is not a standard thing. What do you mean exactly by that? Is it something recent that not all clients support yet? I see that IPFS does even document it as part of their native URL format: https://docs.ipfs.tech/how-to/address-ipfs-on-web/#native-urls

leszko commented 1 year ago

@victorges Actually you're right. I somehow thought that these relative paths are not resolved correctly by IPFS gateways, but I checked a few gateways and all works well. Then, yes, we could just have ipfs:// paths.

So, we have two options. I'd opt for Option 1 because it'll be more consistent between Storj and web3.storage. Otherwise for Storj we'll have relative paths and for web3.storage we'll have IPFS absolute URLs. @victorges @yondonfu wdyt?

Option 1: IPFS URL + PATH

"output": {
    "transcodeFile": {
        "url": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy",
        "hls": {
            "path": "video/index.m3u8"   
        },
        "mp4": {
            "renditions": [
                 { "path": "video/static360p0.mp4" },
                 { "path": "video/static720p0.mp4" },
                 { "path": "video/static1440p0.mp4" }
             ]         
        }
    }
}

The Storj output will look the same, but without url.

Option 2: IPFS Absolute path

"output": {
    "transcodeFile": {
        "hls": {
            "path": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy/video/index.m3u8"   
        },
        "mp4": {
            "renditions": [
                 { "path": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy/video/static360p0.mp4" },
                 { "path": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy/video/static720p0.mp4" },
                 { "path": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy/video/static1440p0.mp4" }
             ]         
        }
    }
}

For Storj we'll have relative paths in path.

victorges commented 1 year ago

@leszko I think the argument for consistency between Storj and web3.storage makes a lot of sense! LGTM

My only suggestions is to call the new field baseUrl instead, to make it explicitly that it needs to be joined with the paths in each file.

Would be even nicer if we could create such baseUrl for the S3 inputs as well, but I think we can't really tell what the public URL is gonna look like without more user input.

leszko commented 1 year ago

Would be even nicer if we could create such baseUrl for the S3 inputs as well, but I think we can't really tell what the public URL is gonna look like without more user input.

Yeah, there may even not be any public URL (if the bucket if private). We could return the whole s3+https:// URL, but I think we should not do it.

leszko commented 1 year ago

I've just fired 4 PRs to change the output as we discussed. PTAL.

leszko commented 1 year ago

FYI: After the latest discussions with @victorges , the output will look like this one:

"output": {
    "transcodeFile": {
        "baseUrl": "ipfs://bafybeifkjw5443v4wsp6q4cjuzboi7nt7i6n6iinyj7ii6fapqsuavg2hy",
        "hls": {
            "path": "video/index.m3u8"   
        },
        "mp4": [
             { "path": "video/static360p0.mp4" },
             { "path": "video/static720p0.mp4" },
             { "path": "video/static1440p0.mp4" }
         ]         
    }
}