mirror of https://bitbucket.org/ausocean/av.git
84 lines
2.4 KiB
Go
84 lines
2.4 KiB
Go
/*
|
|
DESCRIPTION
|
|
extract.go provides an Extractor to get JPEG images from an RTP/JPEG stream
|
|
defined by RFC 2435 (see https://tools.ietf.org/html/rfc2435).
|
|
|
|
AUTHOR
|
|
Saxon Nelson-Milton <saxon@ausocean.org>
|
|
|
|
LICENSE
|
|
Copyright (C) 2019 the Australian Ocean Lab (AusOcean)
|
|
|
|
It is free software: you can redistribute it and/or modify them
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
|
|
*/
|
|
|
|
package mjpeg
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"bitbucket.org/ausocean/av/protocol/rtp"
|
|
)
|
|
|
|
const maxRTPSize = 1500 // Max ethernet transmission unit in bytes.
|
|
|
|
// Extractor is an Extractor for extracting JPEG from an RTP stream.
|
|
type Extractor struct {
|
|
dst io.Writer // The destination we'll be writing extracted JPEGs to.
|
|
}
|
|
|
|
// NewExtractor returns a new Extractor.
|
|
func NewExtractor() *Extractor { return &Extractor{} }
|
|
|
|
// Extract will continously read RTP packets from src containing JPEG (in RTP
|
|
// payload format) and extract the JPEG images, sending them to dst. This
|
|
// function expects that each read from src will provide a single RTP packet.
|
|
func (e *Extractor) Extract(dst io.Writer, src io.Reader, delay time.Duration) error {
|
|
buf := make([]byte, maxRTPSize)
|
|
ctx := NewContext(dst)
|
|
|
|
for {
|
|
n, err := src.Read(buf)
|
|
switch err {
|
|
case nil: // Do nothing.
|
|
case io.EOF:
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("source read error: %v\n", err)
|
|
}
|
|
|
|
// Get payload from RTP packet.
|
|
p, err := rtp.Payload(buf[:n])
|
|
if err != nil {
|
|
return fmt.Errorf("could not get RTP payload: %w\n", err)
|
|
}
|
|
|
|
// Also grab the marker so that we know when the JPEG is finished.
|
|
m, err := rtp.Marker(buf[:n])
|
|
if err != nil {
|
|
return fmt.Errorf("could not read RTP marker: %w", err)
|
|
}
|
|
|
|
err = ctx.ParsePayload(p, m)
|
|
switch err {
|
|
case nil: // Do nothing.
|
|
case ErrNoFrameStart: // If no frame start then we continue until we get one.
|
|
default:
|
|
return fmt.Errorf("could not parse JPEG scan: %w", err)
|
|
}
|
|
}
|
|
}
|