视频编解码类型MJPEG数据格式介绍

Motion JPEG(M-JPEG或MJPEG,Motion Joint Photographic Experts Group,FourCC:MJPG)是一种影像压缩格式,其中每一帧图像都分别使用JPEG编码。M-JPEG常用在数字相机和摄像头之类的图像采集设备上。MJPEG即动态JPEG,按照至少达到25帧/秒速度使用JPEG压缩算法压缩视频信号,完成动态视频的压缩。MJPEG压缩标准是由JPEG专家组制定的,其图像格式是对每一帧JPEG图像进行压缩。MJPEG是一种基于静态图像压缩技术JPEG发展起来的动态图像压缩技术,可以生成序列化的运动图像。实际上MJPEG图像数据流就是一帧一帧的JPEG格式图片

MJPEG只是有帧内压缩(区别于算法更复杂的帧间压缩),只单独的对某一帧进行压缩,而不考虑影像画面中不同帧之间的变化。因此压缩效率比较低,而使用了帧间压缩的现代影像压缩格式(如MPEG1、MPEG2和H.264/MPEG-4 AVC)一般压缩率比较高。

MJPEG是一种基于静态图像JPEG压缩标准的动态图像压缩标准,压缩过程是将视频序列的每一帧视为一幅静止图像进行压缩。因此,要进行MJPEG压缩,首先必须实现静态图像的JPEG压缩。JPEG定义了两种基本的算法:基于DCT的有失真压缩算法和基于DPCM的无失真压缩算法。基于DCT的有失真JPEG压缩算法主要分为5个基本步骤:色彩空间变换及采样、离散余弦变换DCT、量化、Z字形编排、编码。

JPEG是一种很灵活的格式,具有调节图像质量的功能,允许用不同的压缩比例对文件进行压缩,支持多种压缩级别。压缩比越大,品质就越低。

JPEG委员会在制定JPEG标准时,定义了许多标记码(marker)或标记段(marker segments)组成,用来区分和识别图像数据及其相关信息。目前,使用比较广泛的是其交换格式JFIF(Jpeg File Interchange Format)。JPEG的每个标记码都是由2个字节组成,其前一个字节是固定值0xFF,每个标记码之前还可以添加数目不限的0xFF填充字节。JPEG文件中的字节是按照正序排列的,即高位字节在前,低位字节在后

JFIF即JPEG文件交换格式(JPEG File Interchange Format, JFIF)是一个图像文件格式标准。它是一种交换符合JPEG交换格式(JIF)标准的JPEG编码文件的格式。它解决了JIF在简单JPEG编码文件交换方面的一些限制。与所有符号JIF的文件一样,JFIF文件中的图像数据使用JPEG标准的技术压缩,因此JFIF有时被称为”JPEG/JFIF”。在JFIF中,图像样本的存放顺序是从左到右和从上到下。

按照JFIF,JPEG文件由两个部分组成:文件头部分和图像压缩数据。其中文件头部分分为一个一个的段来存储(但并不是全部都是段),段的多少和长度并不确定。只要包含了足够的信息,该JPEG文件就能够被打开。文件头部分的每个段都一定包含两部分,一个是段的标记码,它由两个字节构成:第一个字节是十六进制0xFF,第二个字节对于不同的段,有不同的值。紧接着的两个字节存放的是这个段的长度。这个长度的表示方法是按照高位在前,低位在后。另外,为了避免文件头部分和图像压缩数据部分的冲突,在对图像数据进行huffman编码时如果产生了一个0xFF,那么就用0xFF 0x00代替。因此在对压缩数据部分进行解码时,如果一个0xFF的后面字节不是0x00,那么这个字节没有意义,如果0xFF后一字节为0x00,则将此两个字节作为一个字节0xFF进行处理。由于文件头中包含了解码图像时必须的量化表、Huffman表、图像格式等信息,因此输出的第一帧JPEG数据流必须包含文件头。由于接下来编码的图像都是按照相同的方式进行编码的,因此可以不包含文件头,只需要在编码结束时产生一个表示编码结束的标记,用于区分不同帧图像,解码时在图像头部添加上文件头,将编码图像转变为标准的JPEG图像即可。

JFIF主要标记码:

标记码

数值

描述

SOI(start of image)

FFD8

图像开始

EOI(end of image)

FFD9

图像结束

APP0(application)

FFE0

JFIF应用数据块,必须紧随SOI标记

APPn

FFE1----FFEF

扩展APP0标记段,必须紧随JFIF APP0标记

DQT(define quantization table)

FFDB

量化表,可有多个

SOF(start of frame)

FFC0

一帧图像的开始,C0后的第4,5两个字节表示图像高度;第6,7两个字节表示图像宽度;第8个字节若为1则表示为灰度图,若为3则表示为彩色图

DHT(define Huffman table)

FFC4

Huffman表,可有多个

SOS(start of scan)

FFDA

扫描线开始

DRI(define Restart Interval)

FFDD

 

JFIF APP0标记段:在强制性JFIF APP0标记段中指定图像的参数,可选嵌入未压缩的缩略图

字段

大小(字节)

描述

APP0标记

2

FF E0

长度

2

APP0段外的段长度

标识符

5

4A 46 49 46 00 =”JFIF”的ASCII码,以空字节终止,注:在MJPEG中为41 56 49 31 00 =”AVI1”

JFIF版本

2

第一个字节为主版本,第二个字节为次要版本(01 01表示1.01)

密度单位

1

下列像素密度字段的单位:

00:无单位;width:height像素宽高比=Xdensity:Ydensity

01:每英寸像素(2.54厘米)

02:每厘米像素

Xdensity

2

水平像素密度,不得为零

Ydensity

2

垂直像素密度,不得为零

Xthumbnail

1

嵌入的RGB缩略图的水平像素数,可以为零

Ythumbnail

1

嵌入的RGB缩略图的垂直像素数,可以为零

缩略图数据

3*n

未压缩的24位RGB(每个颜色通道8位)光栅缩略图数据,顺序为R0、G0、B0、…Rn、Gn、Bn;其中n= Xthumbnail* Ythumbnail

JFIF扩展APP0标记段:紧随JFIF APP0标记段的可能是JFIF扩展APP0标记段。此段可能仅存在于JFIF 1.02及更高版本。它允许以3种不同的格式嵌入缩略图。

字段

大小(字节)

描述

APP0标记

2

FF E0

长度

2

不包括APP0标记的段长度

标识符

5

4A 46 58 58 00 =”JFXX”的ASCII码,以空字节终止

缩略图格式

1

指定用于以下嵌入缩略图的数据格式:

10:JPEG格式

11:每个像素1字节调色格式

13:每个像素3字节RGB格式

缩略图数据

可变

取决于缩略图格式

缩略图数据取决于缩略图格式:

使用JPEG编码存储的缩略图

字段

大小(字节)

描述

SOI

2

FF D8

可变

必须为使用YCbCr或仅Y的JIF格式,并且必须不包含JFIF或JFXX段

 

EOI

2

FF D9

注:以上内容主要摘自维基百科:Motion_JPEG  JPEG File Interchange Format

下图是通过MJPEG从usb摄像头获取到的大小为160*120(w*h)的一帧数据,为了便于显示移除了中间的部分编码数据:关键字段已用红框标注

下图是用UltraEdit打开的一个16*16的jpeg图像:关键字段已用红框标注

GitHubhttps://github.com//fengbingchun/OpenCV_Test

  • 4
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Android上解码MJPEG格式的视频流,你可以使用以下步骤: 1. 添加必要的依赖项。在你的Android项目中,添加对OpenCV的依赖项,以便使用其图像处理功能。在项目的build.gradle文件中,添加以下依赖项: ```groovy implementation 'org.opencv:opencv-android:3.4.13' ``` 2. 创建一个自定义的SurfaceView类,并实现SurfaceHolder.Callback接口,以监听SurfaceView的生命周期事件。 ```java public class MJPEGSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private MJPEGDecoder mjpegDecoder; public MJPEGSurfaceView(Context context) { super(context); getHolder().addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { // 在Surface创建时初始化解码器 mjpegDecoder = new MJPEGDecoder(holder.getSurface()); mjpegDecoder.startDecoding(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 在Surface尺寸发生变化时更新解码器 mjpegDecoder.updateSurface(holder.getSurface()); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 在Surface销毁时停止解码器 mjpegDecoder.stopDecoding(); } } ``` 3. 创建一个MJPEGDecoder类,负责接收和解码MJPEG格式的视频流。 ```java public class MJPEGDecoder { private Surface surface; private boolean isDecoding; public MJPEGDecoder(Surface surface) { this.surface = surface; isDecoding = true; } public void startDecoding() { // 开始解码线程 new Thread(new Runnable() { @Override public void run() { while (isDecoding) { // 从MJPEG视频流中获取数据并解码 byte[] frameData = getFrameDataFromStream(); // 使用OpenCV解码图像 Bitmap frame = decodeFrame(frameData); // 将解码后的帧绘制到Surface上 drawFrameToSurface(frame); } } }).start(); } public void updateSurface(Surface surface) { this.surface = surface; } public void stopDecoding() { isDecoding = false; } private byte[] getFrameDataFromStream() { // 从网络或其他来源获取MJPEG视频流数据 // 返回帧的字节数组 } private Bitmap decodeFrame(byte[] frameData) { // 使用OpenCV解码MJPEG帧 Mat frameMat = Imgcodecs.imdecode(new MatOfByte(frameData), Imgcodecs.IMREAD_UNCHANGED); Bitmap frameBitmap = null; if (!frameMat.empty()) { frameBitmap = Bitmap.createBitmap(frameMat.cols(), frameMat.rows(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(frameMat, frameBitmap); } return frameBitmap; } private void drawFrameToSurface(Bitmap frame) { if (frame != null) { Canvas canvas = surface.lockCanvas(null); if (canvas != null) { canvas.drawBitmap(frame, 0, 0, null); surface.unlockCanvasAndPost(canvas); } } } } ``` 4. 在你的Activity中使用自定义的MJPEGSurfaceView来显示MJPEG视频流。 ```java public class MainActivity extends AppCompatActivity { private MJPEGSurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surface_view); } } ``` 确保在布局文件中添加一个MJPEGSurfaceView元素: ```xml <com.example.MJPEGSurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 这样,你就可以在Android上解码和显示MJPEG格式的视频流了。请确保根据你的需求和网络库进行必要的调整和配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值