【问题标题】:Attaching a video stream through the .NET Mirror API通过 .NET Mirror API 附加视频流
【发布时间】:2013-07-12 18:01:44
【问题描述】:

我正在尝试使用 .NET Mirror API 附加视频流,但遇到了一些问题。

我似乎找不到支持此处引用的格式的方法:

POST /upload/mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: multipart/related; boundary="mymultipartboundary"
Content-Length: {length}

--mymultipartboundary
Content-Type: application/json; charset=UTF-8

{ "text": "Skateboarding kittens" }
--mymultipartboundary
Content-Type: video/vnd.google-glass.stream-url

http://example.com/path/to/kittens.mp4
--mymultipartboundary--

我从谷歌看到的最好的信息是使用以下方法进行插入:

/// <summary>
/// Insert a new timeline item in the user's glass with an optional
/// notification and attachment.
/// </summary>
/// <param name='service'>Authorized Mirror service.</param>
/// <param name='text'>Timeline Item's text.</param>
/// <param name='contentType'>
/// Optional attachment's content type (supported content types are
/// "image/*", "video/*" and "audio/*").
/// </param>
/// <param name='attachment'>Optional attachment stream</param>
/// <param name='notificationLevel'>
/// Optional notification level, supported values are null and
/// "AUDIO_ONLY".
/// </param>
/// <returns>
/// Inserted timeline item on success, null otherwise.
/// </returns>
public static TimelineItem InsertTimelineItem(MirrorService service,
    String text, String contentType, Stream attachment,
    String notificationLevel) {

  TimelineItem timelineItem = new TimelineItem();
  timelineItem.Text = text;
  if (!String.IsNullOrEmpty(notificationLevel)) {
    timelineItem.Notification = new NotificationConfig() {
      Level = notificationLevel
    };
  }
  try {
    if (!String.IsNullOrEmpty(contentType) && attachment != null) {
      // Insert both metadata and media.
      TimelineResource.InsertMediaUpload request = service.Timeline.Insert(
          timelineItem, attachment, contentType);
      request.Upload();
      return request.ResponseBody;
    } else {
      // Insert metadata only.
      return service.Timeline.Insert(timelineItem).Fetch();
    }
  } catch (Exception e) {
    Console.WriteLine("An error occurred: " + e.Message);
    return null;
  }
}

但是,此代码将内容作为流“附加”(这对于上传图像非常有用,我已经测试过并且可以使用)。但是,流式视频只需要视频的 URL。

我尝试将 URL 的字符串表示形式作为流发送,但结果只是一个无限加载的视频。

我已经成功地通过使用我的身份验证令牌和上面的 POST 请求发出 cURL 请求来播放视频,所以我知道视频本身不是问题。

有没有人能够让流视频通过 .NET(使用 Mirror API 或使用某种自定义 WebRequest?)我尝试自己从头开始创建 WebRequest,但我得到了 400 个一个回应。

作为参考,我尝试过的其他代码:

var request = WebRequest.CreateHttp(baseAddress + method);
request.Method = "POST";
request.Headers.Add("Authorization", string.Format("Bearer {0}", auth));

string itemJson = JsonConvert.SerializeObject(item.Item, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });

 string contentFormat = "--MyBound\nContent-Type: application/json; charset=UTF-8\n\n{0}\n--MyBound\nContent-Type: video/vnd.google-glass.stream-url\n\n{1}\n--MyBound--";
 string content = string.Format(contentFormat, new[] { itemJson, item.VideoUrl });
 request.ContentLength = content.Length;
 request.ContentType = "multipart/related; boundary=\"MyBound\"";
 var rs = request.GetRequestStream();
 using (var sw = new StreamWriter(rs))
 {
     sw.Write(content);
 }

 var response = request.GetResponse();

其中 item 是我编写的一个类,其中包含作为字符串的 VideoUrl 和 Item(来自 Mirror API 的 TimelineItem),而我正在使用的视频 Url 是:

http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8

提前谢谢大家!

【问题讨论】:

    标签: google-mirror-api google-glass


    【解决方案1】:

    我用下面的代码成功了。

     String mediaLink = "url_to_your_video.mp4";
            String message = "you_message";
    
    MirrorService Service = new MirrorService(new BaseClientService.Initializer()
                                                              {
                                                                  Authenticator = Utils.GetAuthenticatorFromState(state)
                                                              });
    
                TimelineItem timelineItem = new TimelineItem();
    
                timelineItem.Creator = new Contact()
                {
                    Id = Config.CREATOR_ID,
                    DisplayName = Config.DISPLAY_NAME,
                };
    
    
                timelineItem.Notification = new NotificationConfig() { Level = "DEFAULT" };
                timelineItem.MenuItems = new List<MenuItem>()
                                             {
                                                 new MenuItem() {Action = "NAVIGATE"},
                                                 new MenuItem() {Action = "DELETE"},
                                                 new MenuItem() {Action = "SHARE"},
                                             };
    
    
                if (!String.IsNullOrEmpty(mediaLink))
                    {
                    Stream stream = null;
                    if (mediaLink.StartsWith("/"))
                        {
                        stream = new StreamReader(Server.MapPath(mediaLink)).BaseStream;
                        }
                    else
                        {
                        HttpWebRequest request = WebRequest.Create(mediaLink) as HttpWebRequest;
                        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                        byte[] b = null;
                        using (Stream streamFromWeb = response.GetResponseStream())
                        using (MemoryStream ms = new MemoryStream())
                            {
                            int count = 0;
                            do
                                {
                                byte[] buf = new byte[1024];
                                count = streamFromWeb.Read(buf, 0, 1024);
                                ms.Write(buf, 0, count);
                                } while (streamFromWeb.CanRead && count > 0);
                            b = ms.ToArray();
                            stream = new MemoryStream(b);
                            }
                        }
    
    
                    Service.Timeline.Insert(timelineItem, stream, "video/mp4").Upload();
                    }
                else
                    {
                    Service.Timeline.Insert(timelineItem).Fetch();
                    }
    

    【讨论】:

      【解决方案2】:

      Sanath 的代码适用于小文件,但您真的不想将任何大文件的二进制文件上传到 Glass。

      Glass 网站上的文档有点误导,他们详细介绍了如何进行多部分上传,但随后告诉您它们不是一个好主意,并简要提及您应该如何做。

      Glass 实际上支持从时间线直接进行渐进式下载和 hls 流式传输。您需要创建一个带有缩略图参考的标准图像卡,然后将 PLAY_VIDEO 菜单项添加到您的菜单项列表中。我已经有一段时间没有进行任何 .net 编程了,但我猜这应该可以工作。

      new MenuItem() {Action = "PLAY_VIDEO", Payload = mediaLink}
      

      【讨论】:

      • 不,这不会起作用,除非像其他语言一样,菜单项没有 Payload 属性。真的是脖子疼。
      • 就像我说的,有一段时间没有做 .net 了。当他们介绍 PLAY_VIDEO 操作时,我需要更新包含菜单项定义的 php Mirror_Client 库。如果该属性不存在,您可能需要执行相同的操作或手动更新库以包含该属性。
      • 对不起弗拉克。我的 Mirror API 几个月没有更新。昨天我更新了它,你的方法可以用它谢谢
      • 阿马兰,你确定 Google.Apis.Mirror.v1.Data.MenuItem 有 Payload 吗?
      【解决方案3】:

      无限加载可能意味着视频格式不正确或不再提供。我不认为这里是这种情况。

      您提到的视频网址与我可以使用此答案中记录的 Curl 开始工作的视频网址相同:

      Attaching video with video/vnd.google-glass.stream-url after Update XE6

      (找我的答案,不是选中的那个)

      这意味着您的请求中有问题,响应是什么?这是我发送工作请求时的示例响应:

          {
       "kind": "mirror#timelineItem",
       "id": "44359ebc-ff49-4d48-a609-2f6ab1354ae3",
       "selfLink": "https://www.googleapis.com/mirror/v1/timeline/44359ebc-ff49-4d48-a
      609-2f6ab1354ae3",
       "created": "2013-07-13T05:05:30.004Z",
       "updated": "2013-07-13T05:05:30.004Z",
       "etag": "\"ZECOuWdXUAqVdpmYErDm2-91GmY/h_jXHSw50TrLSr94HZGFIGAlPxs\"",
       "text": "Sweetie",
       "attachments": [
        {
         "id": "bs:9088a6e2-b8ad-4e1d-a544-5d7e858e5e3f",
         "contentType": "video/vnd.google-glass.stream-url",
         "contentUrl": "https://www.googleapis.com/mirror/v1/timeline/44359ebc-ff49-4d
      48-a609-2f6ab1354ae3/attachments/bs:9088a6e2-b8ad-4e1d-a544-5d7e858e5e3f?alt=med
      ia"
        }
       ]
      }
      

      我刚做了这个,确实看到了在 Glass 上播放的哔声 - bop 视频。

      所以,检查响应,并看看你是否可以打印出请求,我的看起来像这样:

      --mymultipartboundary
      Content-Type: application/json; charset=UTF-8
      
      { "text": "Sweetie" }
      --mymultipartboundary
      Content-Type: video/vnd.google-glass.stream-url
      
      http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
      --mymultipartboundary--
      

      查看请求的一种方法是使用像 Charles、Fiddler 或 Wireshark 这样的嗅探器,如果这不适合您将请求指向这样的 php 文件,请查看 out.txt(注意我的 php 不是太棒了,所以你可能需要修改它):

      <?php
      
      $file = 'out.txt';
      
      $current .= print_r($_GET, true);
      $current .= print_r($_POST,true);
      $current .= print_r(getallheaders(),true);
      
      file_put_contents($file, $current);
      
      ?>
      

      我认为您应该专注于您发布的代码的第二部分,它看起来非常接近我的工作,只需打印出其中的一些项目,通过与我的示例相比应该很清楚出了什么问题。

      【讨论】:

      • 非常感谢您的回复!
      • 抱歉,之前的评论让我发疯了。 itemJson 看起来像: {"Text":"Testing..."} 我的响应是: response = { "error": { "errors": [ { "domain": "global", "reason": "required" , "message": "Required" } ], "code": 400, "message": "Required" } } 我似乎无法打印出 webrequest...您有建议的方法吗?我已经尝试在提琴手中对其进行监控,但没有看到请求。
      • 我用一些想法更新了我的答案以获得请求,很高兴知道它与身份验证无关,看看你是否能让那个 php 工作正常,虽然 Fiddler 是正确的想法,那会更好.
      • 非常感谢。我想通了......我正在使用 Newtonsoft 序列化 TimelineItem,但它是基于成员名称序列化,而不是为每个成员分配的 JsonProperty。这是一个区分大小写的问题,加上需要“文本”(因为我传递的是“文本”,所以没有找到它)。
      • 很高兴它成功了,有趣的是这是我的第一个猜测,当你发布 JSON 时我应该看到的,但是格式使它更难看到。未来的提示,如果您想分享回格式化的文本,请将其作为编辑放在原始问题中,然后在您的评论中引用更改。恭喜你解决了这个问题!
      猜你喜欢
      • 2019-01-31
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 2022-06-17
      • 1970-01-01
      • 2020-10-18
      • 2016-07-09
      • 2019-12-02
      相关资源
      最近更新 更多