mirror of
https://github.com/aler9/gortsplib
synced 2025-09-27 03:25:52 +08:00
simplify client-record-format-mpeg4audio (#709)
This commit is contained in:
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- run: sudo apt update && sudo apt install -y libavcodec-dev libswscale-dev libswresample-dev
|
||||
- run: sudo apt update && sudo apt install -y libavcodec-dev libswscale-dev
|
||||
|
||||
- run: make test-nodocker
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
// This example shows how to
|
||||
// 1. generate a dummy G711 audio stream
|
||||
// 2. connect to a RTSP server, find a back channel that supports G711
|
||||
// 3. route the packets from GStreamer to the channel
|
||||
// 3. route the G711 stream to the channel
|
||||
|
||||
func multiplyAndDivide(v, m, d int64) int64 {
|
||||
secs := v / d
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a AV1 format
|
||||
// 2. check if there's a AV1 stream
|
||||
// 3. decode the AV1 stream into RGBA frames
|
||||
// 4. convert RGBA frames to JPEG images and save them on disk
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a AV1 format
|
||||
// 2. check if there's a AV1 stream
|
||||
// 3. decode the AV1 stream into RGBA frames
|
||||
|
||||
// This example requires the FFmpeg libraries, that can be installed with this command:
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a G711 format
|
||||
// 2. check if there's a G711 stream
|
||||
// 3. decode the G711 stream into audio samples
|
||||
|
||||
func main() {
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a H264 format and an MPEG-4 audio format
|
||||
// 2. check if there's a H264 stream and an MPEG-4 audio format
|
||||
// 3. save the content of those formats in a file in MPEG-TS format
|
||||
|
||||
func main() {
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a H264 format
|
||||
// 2. check if there's a H264 stream
|
||||
// 3. save the content of the format in a file in MPEG-TS format
|
||||
|
||||
func main() {
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a H264 format
|
||||
// 2. check if there's a H264 stream
|
||||
// 3. decode the H264 stream into RGBA frames
|
||||
// 4. convert RGBA frames to JPEG images and save them on disk
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a H265 format
|
||||
// 2. check if there's a H265 stream
|
||||
// 3. save the content of the format in a file in MPEG-TS format
|
||||
|
||||
func main() {
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a H265 format
|
||||
// 2. check if there's a H265 stream
|
||||
// 3. decode the H265 stream into RGBA frames
|
||||
// 4. convert RGBA frames to JPEG images and save them on disk
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a M-JPEG format
|
||||
// 2. check if there's a M-JPEG stream
|
||||
// 3. get JPEG images of that format
|
||||
// 4. decode JPEG images into RGBA frames
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// This example shows how to
|
||||
// 1. connect to a RTSP server
|
||||
// 2. check if there's a Opus format
|
||||
// 2. check if there's a Opus stream
|
||||
// 3. save the content of the format in a file in MPEG-TS format
|
||||
|
||||
func main() {
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
// 4. write RTP packets to the server
|
||||
|
||||
// This example requires the FFmpeg libraries, that can be installed with this command:
|
||||
// apt install -y libavcodec-dev libswresample-dev gcc pkg-config
|
||||
// apt install -y libavcodec-dev gcc pkg-config
|
||||
|
||||
func multiplyAndDivide(v, m, d int64) int64 {
|
||||
secs := v / d
|
||||
@@ -45,7 +45,7 @@ func main() {
|
||||
Config: &mpeg4audio.Config{
|
||||
Type: mpeg4audio.ObjectTypeAACLC,
|
||||
SampleRate: 48000,
|
||||
ChannelCount: 2,
|
||||
ChannelCount: 1,
|
||||
},
|
||||
SizeLength: 13,
|
||||
IndexLength: 3,
|
||||
|
@@ -2,13 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// #cgo pkg-config: libavcodec libavutil libswresample
|
||||
// #cgo pkg-config: libavcodec libavutil
|
||||
// #include <libavcodec/avcodec.h>
|
||||
// #include <libswresample/swresample.h>
|
||||
// #include <libavutil/opt.h>
|
||||
// #include <libavutil/channel_layout.h>
|
||||
import "C"
|
||||
@@ -21,30 +20,19 @@ func frameLineSize(frame *C.AVFrame) *C.int {
|
||||
return (*C.int)(unsafe.Pointer(&frame.linesize[0]))
|
||||
}
|
||||
|
||||
func switchEndianness16(samples []byte) []byte {
|
||||
ls := len(samples)
|
||||
for i := 0; i < ls; i += 2 {
|
||||
samples[i], samples[i+1] = samples[i+1], samples[i]
|
||||
}
|
||||
return samples
|
||||
}
|
||||
|
||||
func littleEndianToFloat(swrCtx *C.struct_SwrContext, samples []byte) ([]byte, error) {
|
||||
func bigEndianS16ToFloat32(samples []byte) ([]byte, error) {
|
||||
sampleCount := len(samples) / 2
|
||||
outSize := len(samples) * 2
|
||||
outSamples := make([]byte, outSize)
|
||||
|
||||
var p runtime.Pinner
|
||||
p.Pin(&outSamples[0])
|
||||
p.Pin(&samples[0])
|
||||
defer p.Unpin()
|
||||
|
||||
outBufs := (*C.uint8_t)(&outSamples[0])
|
||||
inBufs := (*C.uint8_t)(&samples[0])
|
||||
|
||||
res := C.swr_convert(swrCtx, &outBufs, (C.int)(sampleCount), &inBufs, (C.int)(sampleCount))
|
||||
if res < 0 {
|
||||
return nil, fmt.Errorf("swr_convert() failed")
|
||||
for i := 0; i < sampleCount; i++ {
|
||||
s := (int16(samples[(i*2)]) << 8) | int16(samples[(i*2)+1])
|
||||
f := float32(s) / 32767
|
||||
b := math.Float32bits(f)
|
||||
outSamples[(i * 4)] = byte(b)
|
||||
outSamples[(i*4)+1] = byte(b >> 8)
|
||||
outSamples[(i*4)+2] = byte(b >> 16)
|
||||
outSamples[(i*4)+3] = byte(b >> 24)
|
||||
}
|
||||
|
||||
return outSamples, nil
|
||||
@@ -58,7 +46,6 @@ type mp4aEncoder struct {
|
||||
|
||||
codecCtx *C.AVCodecContext
|
||||
frame *C.AVFrame
|
||||
swrCtx *C.struct_SwrContext
|
||||
pkt *C.AVPacket
|
||||
samplesBuffer []byte
|
||||
samplesBufferPTS int64
|
||||
@@ -105,48 +92,8 @@ func (d *mp4aEncoder) initialize() error {
|
||||
return fmt.Errorf("av_frame_get_buffer() failed")
|
||||
}
|
||||
|
||||
d.swrCtx = C.swr_alloc()
|
||||
if d.swrCtx == nil {
|
||||
C.av_frame_free(&d.frame)
|
||||
C.avcodec_close(d.codecCtx)
|
||||
return fmt.Errorf("swr_alloc() failed")
|
||||
}
|
||||
|
||||
cstr := C.CString("out_channel_layout")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_channel_layout(unsafe.Pointer(d.swrCtx), cstr, (C.int64_t)(d.codecCtx.channel_layout), 0)
|
||||
|
||||
cstr = C.CString("out_sample_fmt")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_int(unsafe.Pointer(d.swrCtx), cstr, C.AV_SAMPLE_FMT_FLTP, 0)
|
||||
|
||||
cstr = C.CString("out_sample_rate")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_int(unsafe.Pointer(d.swrCtx), cstr, 48000, 0)
|
||||
|
||||
cstr = C.CString("in_channel_layout")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_channel_layout(unsafe.Pointer(d.swrCtx), cstr, (C.int64_t)(d.codecCtx.channel_layout), 0)
|
||||
|
||||
cstr = C.CString("in_sample_fmt")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_int(unsafe.Pointer(d.swrCtx), cstr, C.AV_SAMPLE_FMT_S16, 0)
|
||||
|
||||
cstr = C.CString("in_sample_rate")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.av_opt_set_int(unsafe.Pointer(d.swrCtx), cstr, 48000, 0)
|
||||
|
||||
res = C.swr_init(d.swrCtx)
|
||||
if res < 0 {
|
||||
C.swr_free(&d.swrCtx)
|
||||
C.av_frame_free(&d.frame)
|
||||
C.avcodec_close(d.codecCtx)
|
||||
return fmt.Errorf("swr_init() failed")
|
||||
}
|
||||
|
||||
d.pkt = C.av_packet_alloc()
|
||||
if d.pkt == nil {
|
||||
C.swr_free(&d.swrCtx)
|
||||
C.av_frame_free(&d.frame)
|
||||
C.avcodec_close(d.codecCtx)
|
||||
return fmt.Errorf("av_packet_alloc() failed")
|
||||
@@ -158,18 +105,14 @@ func (d *mp4aEncoder) initialize() error {
|
||||
// close closes the decoder.
|
||||
func (d *mp4aEncoder) close() {
|
||||
C.av_packet_free(&d.pkt)
|
||||
C.swr_free(&d.swrCtx)
|
||||
C.av_frame_free(&d.frame)
|
||||
C.avcodec_close(d.codecCtx)
|
||||
}
|
||||
|
||||
// encode encodes LPCM samples into Opus packets.
|
||||
func (d *mp4aEncoder) encode(samples []byte) ([][]byte, int64, error) {
|
||||
// convert from big-endian to little-endian
|
||||
samples = switchEndianness16(samples)
|
||||
|
||||
// convert from little-endian to float
|
||||
samples, err := littleEndianToFloat(d.swrCtx, samples)
|
||||
// convert from big-endian signed 16-bit integer to float32
|
||||
samples, err := bigEndianS16ToFloat32(samples)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user