DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: gtgtfgtgdsf12S
今日帖子: 11
在线用户: 10
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 nickemma (N.E) ▲▲▲▲△ -
注册会员
2018/10/2 15:36:51
标题:
[开源]FMX跨平台平台 RTC HTTPClient 解码MJPEG视频流(WiFi小车视频解码) 浏览:587
加入我的收藏
楼主: WiFi小车上位机程序:http://bbs.2ccc.com/topic.asp?topicid=552839
WiFi小车制作共享  :http://bbs.2ccc.com/topic.asp?topicid=552684

现在把WiFi小车解码MJPEG视频流的跨平台代码附上,代码粗糙,大神轻拍。

内含两种模式解码:
1、标准 MJPEG 视频流模式;
2、Snapshot 静态图片获取模式
此帖子包含附件:nickemma_2018102153651.rar 大小:8.7K
----------------------------------------------
-
作者:
男 nickemma (N.E) ▲▲▲▲△ -
注册会员
2018/10/2 16:10:27
1楼: 本人非专业编程人士,那位大神帮忙看看,视频解码核心部分代码,能否再优化优化,提高效率。

视频解码接收到的数据包有下列情况:
1、有帧头,无帧尾
2、有帧尾,无帧头
3、无帧头、无帧尾
   --不是帧内容数据
   --是帧内容数据
4、多帧头、多帧尾
   --帧头对于帧尾
   --帧头少于帧尾
   --帧头等于帧尾

以上 1~3 点,视频解码的时候只是一帧、半帧内容,但若然出现第4种情况:接收到一个含有5帧数据的大数据包的时,遍历一次全部数据将会有点吃力。

//遍历接收到的数据,并记录入 FBegins(帧头位置) FEnds(帧尾位置) 数组
//帧头$FF$D8 帧尾$FF$D9 帧头至帧尾数据合并成完整一帧
procedure TMainForm.FindAllBytes(const ABuffer: array of Byte);
var
  i: Integer;
begin
  SetLength(FBegins, 0);
  SetLength(FEnds, 0);

  for i := Low(ABuffer) to High(ABuffer) -1 do
  begin
    if ABuffer[i] = $FF then
    begin
      if ABuffer[i + 1] = $D8 then
      begin
        SetLength(FBegins, Length(FBegins) + 1);
        FBegins[High(FBegins)] := i;
      end
      else if ABuffer[i + 1] = $D9 then
      begin
        SetLength(FEnds, Length(FEnds) + 1);
        FEnds[High(FEnds)] := i + 2;
      end;
    end;
  end;
end;

//数据包帧解码
var
  FReceived: RtcByteArray; //array of Byte
  FLength, LengthBegin, LengthEnd, i: Integer;
begin
  FReceived := ReadEx;
  FLength := Length(FReceived);

  FindAllBytes(FReceived);
  LengthBegin := Length(FBegins);
  LengthEnd := Length(FEnds);

  if (LengthBegin = 1) and (LengthEnd = 0) then
  begin//有帧头,无帧尾
    FMS.Write(FReceived[FBegins[0]], FLength - FBegins[0]);
    FMS.Seek(0, soFromEnd);

    FFrameStart := True;
  end
  else if (LengthBegin = 0) and (LengthEnd = 1) then
  begin//有帧尾,无帧头
    FMS.Write(FReceived[0], FEnds[0]);
    Image1.Bitmap.LoadFromStream(FMS);
    FMS.Clear;

    FFrameStart := False;
  end
  else if (LengthBegin = 0) and (LengthEnd = 0) and (FFrameStart) then
  begin//无帧头、无帧尾,是帧内容数据
    FMS.Write(FReceived[0], FLength);
    FMS.Seek(0, soFromEnd);

    FFrameStart := True;
  end
  else if (LengthBegin > 0) and (LengthEnd > 0) and (FBegins[0] < FEnds[0]) then
  begin //多帧,而且帧头小于帧尾。此情况不存在帧头数量少于帧尾数量
    //先循环载入帧
    for i := Low(FEnds) to High(FEnds) do
    begin
      FMS.Write(FReceived[FBegins[i]], FEnds[i] - FBegins[i]);
      Image1.Bitmap.LoadFromStream(FMS);
      FMS.Clear;
    end;
    FFrameStart := False;

    //如果还多一个帧头
    if LengthBegin - LengthEnd = 1 then
    begin
      FMS.Write(FReceived[FBegins[High(FBegins)]], FLength - FBegins[High(FBegins)]);
      FMS.Seek(0, soFromEnd);

      FFrameStart := True;
    end;
  end
  else if (LengthBegin > 0) and (LengthEnd > 0) and (FBegins[0] > FEnds[0]) then
  begin //多帧,而且帧头大于帧尾。此情况不存在帧头多于帧尾数量
    //先载入上一帧帧尾
    FMS.Write(FReceived[0], FEnds[0]);
    Image1.Bitmap.LoadFromStream(FMS);
    FMS.Clear;
    FFrameStart := False;

    if (LengthBegin <> LengthEnd) then//帧头数量少于帧尾数量
    begin
      for i := Low(FBegins) to High(FBegins) do
      begin
        FMS.Write(FReceived[FBegins[i]], FEnds[i + 1] - FBegins[i]);
        Image1.Bitmap.LoadFromStream(FMS);
        FMS.Clear;
      end;
      FFrameStart := False;
    end
    else //帧头数量等于帧尾数量
    begin
      for i := Low(FBegins) to High(FBegins) - 1 do
      begin
        FMS.Write(FReceived[FBegins[i]], FEnds[i + 1] - FBegins[i]);
        Image1.Bitmap.LoadFromStream(FMS);
        FMS.Clear;
      end;

      FMS.Write(FReceived[FBegins[High(FBegins)]], FLength - FBegins[High(FBegins)]);
      FMS.Seek(0, soFromEnd);

      FFrameStart := True;
    end;
  end;
end;
----------------------------------------------
-
作者:
男 star5 (星五) ★☆☆☆☆ -
盒子活跃会员
2018/10/3 15:58:42
2楼: 感谢分享。
----------------------------------------------
博客 - http://offeu.com
脚本模型 - http://webpascal.com
作者:
男 bbnn38 (伟大的咸鱼) ▲▲▲▲△ -
注册会员
2018/10/3 20:48:53
3楼: 留名关注
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2018/10/6 0:54:09
4楼: 楼主,因为视频的每一帧的大小不同,如果是流式发送和接收,你是没办法找到一帧的开头和结尾的。如果搜索特殊的字节串来当作分隔符,那也是效率很低的。

所以,通常这种情况下,都是依靠索引的方式。如果是流媒体,就是类似链表的方式,一个固定长度的头,头里面有后面跟随的数据的长度。这样一个头,一串数据,再一个头,一串数据。只要一开始的头抓到,后面就顺理成章。

如果是文件媒体,比如 MP4,则是把索引写入了文件结尾。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行15.625毫秒 RSS