Firefly开源社区

标题: 回调函数,无法正常解析rtm流传入的图像的数据 [打印本页]

作者: chenwusong    时间: 2024-9-13 15:52
标题: 回调函数,无法正常解析rtm流传入的图像的数据
我在本机的1935部署了rtmp视频流,使demo.p已经可以正常读取到视频流,并且播放出去。然后我开始启动回调函数对数据进行处理,不过目前demo.py里的回调函数,无法解析出图像数据,这个回调函数,可以正常从/dev/video0里读取的图像,但是无法解析rtmp流的图像。


  1. #!/usr/bin/env python
  2. #coding:utf-8
  3. """
  4.   Author:   陈 --<>
  5.   Purpose:
  6.   Created: 202409
  7. """

  8. import argparse
  9. import re
  10. import sys
  11. import os
  12. import stat
  13. import time
  14. import cv2
  15. import copy
  16. import json

  17. import numpy as np

  18. import ff_pymedia as m


  19. def showText(img, text):
  20.     return cv2.putText(img, f'fps:{text}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 1, cv2.LINE_AA)

  21. def align(x, a):
  22.     return (x + a - 1) & ~(a - 1)


  23. def call_back1(obj, MediaBuffer):
  24.     print('czj',time.time())
  25.     vb = m.VideoBuffer.from_base(MediaBuffer)
  26.     data = vb.getActiveData()
  27.     try:
  28.         img = data.reshape((vb.getImagePara().vstride, vb.getImagePara().hstride, 3))
  29.         print(img.shape)
  30.     except:
  31.         pass
  32.     #np.save(f'cache/{time.time()}.npy',data)
  33.     print(type(data),data.shape,vb.getImagePara().vstride,vb.getImagePara().hstride,data[:20])
  34.     a = MediaBuffer.getActiveData()
  35.     print(a.shape)
  36.     #obj.write(a)

  37.     return MediaBuffer



  38. def get_parameters():
  39.     parser = argparse.ArgumentParser()
  40.     parser.add_argument("-i", "--input_source", dest='input_source', type=str, help="input source")
  41.     parser.add_argument("-f", "--save_file", dest='save_file', type=str, help="Enable save source output data to file, set filename, default disabled")
  42.     parser.add_argument("-o", "--output", dest='output', type=str, help="Output image size, default same as input")
  43.     parser.add_argument("-b", "--outputfmt", dest='outputfmt', type=str, default="NV12", help="Output image format, default NV12")
  44.     parser.add_argument("-e", "--encodetype", dest='encodetype', type=int, default=-1, help="Encode encode, set encode type, default disabled")
  45.     parser.add_argument("-m", "--enmux", dest='enmux', type=str, help="Enable save encode data to file. Enable package as mp4, mkv, flv, ts, ps or raw stream files, muxer type depends on the filename suffix. default disabled")
  46.     parser.add_argument("-p", "--port", dest='port', type=int, default=0, help="Enable push stream, default rtsp stream, set push port, depend on encode enabled, default disabled\n")
  47.     parser.add_argument("--push_type", dest='push_type', type=int, default=0, help="Set push stream type, default rtsp. e.g. --push_type 1\n")
  48.     parser.add_argument("--rtmp_url", dest='rtmp_url', type=str, help="Set the rtmp client push address. e.g. --rtmp_url rtmp://xxx\n")
  49.     parser.add_argument("--rtsp_transport", dest='rtsp_transport', type=int, default=0, help="Set the rtsp transport type, default 0(udp)")
  50.     parser.add_argument("-s", "--sync", dest="sync", type=int, default=-1, help="Enable synchronization module, default disabled. e.g. -s 1")
  51.     parser.add_argument("--audio", dest='audio', type=bool, default=False, help="Enable audio, default disabled.")
  52.     parser.add_argument("--aplay", dest='aplay', type=str, help="Enable play audio, default disabled. e.g. --aplay plughw:3,0")
  53.     parser.add_argument("--arecord", dest='arecord', type=str, help="Enable record audio, default disabled. e.g. --arecord plughw:3,0")
  54.     parser.add_argument("-r", "--rotate", dest='rotate',type=int, default=0, help="Image rotation degree, default 0" )
  55.     parser.add_argument("-d", "--drmdisplay", dest='drmdisplay', type=int, default=-1, help="Drm display, set display plane, set 0 to auto find plane")
  56.     parser.add_argument("--connector", dest='connector', type=int, default=0, help="Set drm display connector, default 0 to auto find connector")
  57.     parser.add_argument("-z","--zpos", dest='zpos', type=int, default=0xff, help="Drm display plane zpos, default auto select")
  58.     parser.add_argument("-c", "--cvdisplay", dest='cvdisplay', type=int, default=0, help="OpenCv display, set window number, default 0")
  59.     parser.add_argument("-x", "--x11display", dest='x11display', type=int, default=0, help="X11 window displays, render the video using gles. default disabled")
  60.     parser.add_argument("-l", "--loop", dest='loop', action='store_true', help="Loop reads the media file.")
  61.     parser.add_argument("--gb28181_user_id", dest='gb28181_user_id', type=str, help="Enable gb28181 client, default disabled. set user id.")
  62.     parser.add_argument("--gb28181_server_id", dest='gb28181_server_id', type=str, help="Set the server id of gb28181 client.")
  63.     parser.add_argument("--gb28181_server_ip", dest='gb28181_server_ip', type=str, help="Set the server ip of gb28181 client\.")
  64.     parser.add_argument("--gb28181_server_port", dest='gb28181_server_port', type=int, default=5060, help="Set the server port of gb28181 client.")
  65.     return parser.parse_args()

  66. def main():

  67.     args = get_parameters()
  68.     last_audio_module = None
  69.     input_audio_source = None

  70.     if args.input_source is None:
  71.         return 1
  72.     elif args.input_source.startswith("rtsp://"):
  73.         print("input source is a rtsp url")
  74.         input_source = m.ModuleRtspClient(args.input_source, m.RTSP_STREAM_TYPE(args.rtsp_transport), True, args.audio)
  75.     elif args.input_source.startswith("rtmp://"):
  76.         print("input source is a rtmp url")
  77.         input_source = m.ModuleRtmpClient(args.input_source)
  78.     else:
  79.         is_stat = os.stat(args.input_source)
  80.         if stat.S_ISCHR(is_stat.st_mode):
  81.             print("input source is a camera device.")
  82.             input_source = m.ModuleCam(args.input_source)
  83.         elif stat.S_ISREG(is_stat.st_mode):
  84.             print("input source is a regular file.")
  85.             input_source = m.ModuleFileReader(args.input_source, args.loop);
  86.         else:
  87.             print("{} is not support.".format(args.input_source))
  88.             return 1

  89.     ret = input_source.init()
  90.     last_module = input_source
  91.     if ret < 0:
  92.         print("input_source init failed")
  93.         return 1

  94.     if args.sync == -1:
  95.         sync = None
  96.     else:
  97.         sync = m.Synchronize(m.SynchronizeType(args.sync))

  98.     if args.arecord is not None:
  99.         s_info = m.SampleInfo()
  100.         s_info.channels = 2
  101.         s_info.fmt = m.SAMPLE_FMT_S16
  102.         s_info.nb_samples = 1024
  103.         s_info.sample_rate = 48000
  104.         capture = m.ModuleAlsaCapture(args.arecord, s_info)
  105.         ret = capture.init()
  106.         if ret < 0:
  107.             print("Failed to init arecord")
  108.             return ret
  109.         input_audio_source = capture
  110.         last_audio_module = capture

  111.         aac_enc = m.ModuleAacEnc()
  112.         aac_enc.setProductor(last_audio_module)
  113.         ret = aac_enc.init()
  114.         if ret < 0:
  115.             print("Failed to init aac_enc")
  116.             return ret
  117.         last_audio_module = aac_enc


  118.     if args.aplay is not None:
  119.         aac_dec = m.ModuleAacDec()
  120.         if last_audio_module != None:
  121.             aac_dec.setProductor(last_audio_module)
  122.         else:
  123.             aac_dec.setProductor(last_module)
  124.         ret = aac_dec.init()
  125.         if ret < 0:
  126.             print("aac_dec init failed")
  127.             return 1

  128.         aplay = m.ModuleAlsaPlayBack(args.aplay)
  129.         aplay.setProductor(aac_dec)
  130.         aplay.setSynchronize(sync)
  131.         ret = aplay.init()
  132.         if ret < 0:
  133.             print("aplay init failed")
  134.             return 1

  135.     input_para = last_module.getOutputImagePara()
  136.     #input_para = last_module.getOutputImagePara()
  137.     #last_module.setOutputDataCallback({}, call_back1)

  138.     if input_para.v4l2Fmt == m.v4l2GetFmtByName("H264") or \
  139.         input_para.v4l2Fmt == m.v4l2GetFmtByName("MJPEG")or \
  140.         input_para.v4l2Fmt == m.v4l2GetFmtByName("H265"):
  141.         dec = m.ModuleMppDec()
  142.         dec.setProductor(last_module)
  143.         ret = dec.init()
  144.         if ret < 0:
  145.             print("dec init failed")
  146.             return 1
  147.         last_module = dec

  148.     input_para = last_module.getOutputImagePara()

  149.     #last_module.setOutputDataCallback({}, call_back1)

  150.     output_para=m.ImagePara(input_para.width, input_para.height, input_para.hstride, input_para.vstride, m.v4l2GetFmtByName(args.outputfmt))
  151.     if args.output is not None:
  152.         match = re.match(r"(\d+)x(\d+)", args.output)
  153.         if match:
  154.             width, height = map(int, match.groups())
  155.             output_para.width = width
  156.             output_para.height = height

  157.     if args.rotate !=0 or input_para.height != output_para.height or \
  158.         input_para.height != output_para.height or \
  159.         input_para.width != output_para.width or \
  160.         input_para.v4l2Fmt != output_para.v4l2Fmt:
  161.         rotate = m.RgaRotate(args.rotate)

  162.         if rotate == m.RgaRotate.RGA_ROTATE_90 or rotate == m.RgaRotate.RGA_ROTATE_270:
  163.             t = output_para.width
  164.             output_para.width = output_para.height
  165.             output_para.height = t

  166.         # hstride and vstride are aligned to 16 bytes
  167.         output_para.hstride = align(output_para.width, 16)
  168.         output_para.vstride = align(output_para.height, 16)

  169.         rga = m.ModuleRga(output_para, rotate)
  170.         rga.setProductor(last_module)
  171.         rga.setBufferCount(2)
  172.         ret = rga.init()
  173.         if ret < 0:
  174.             print("rga init failed")
  175.             return 1
  176.         last_module = rga

  177.     cv_display = None

  178.     #input_source.setOutputDataCallback({}, call_back1)

  179.     last_module.setOutputDataCallback({}, call_back1)

  180.     if args.drmdisplay != -1:
  181.         input_para = last_module.getOutputImagePara()
  182.         #last_module.setOutputDataCallback({}, call_back1)

  183.         drm_display = m.ModuleDrmDisplay()
  184.         drm_display.setPlanePara(m.v4l2GetFmtByName("NV12"), args.drmdisplay,
  185.                                  m.PLANE_TYPE.PLANE_TYPE_OVERLAY_OR_PRIMARY, args.zpos, 1, args.connector)
  186.         drm_display.setProductor(last_module)
  187.         drm_display.setSynchronize(sync)
  188.         ret = drm_display.init()
  189.         if ret < 0:
  190.             print("drm display init failed")
  191.             return 1
  192.         else:
  193.             t_h = drm_display.getDisplayPlaneH()
  194.             t_w = drm_display.getDisplayPlaneW()
  195.             w = min(t_w, input_para.width)
  196.             h = min(t_h, input_para.height)
  197.             x = (t_w - w) // 2
  198.             y = (t_h - h) // 2
  199.             drm_display.setWindowSize(x, y, w, h)
  200.     else:
  201.         if args.x11display != 0:
  202.             x11_display = m.ModuleRendererVideo(args.input_source)
  203.             x11_display.setProductor(last_module)
  204.             x11_display.setSynchronize(sync)
  205.             ret = x11_display.init()
  206.             if ret < 0:
  207.                 print("ModuleRendererVideo init failed")
  208.                 return 1

  209.         if args.cvdisplay > 0:
  210.             if not cv2_enable:
  211.                 print("Run 'pip3 install opencv-python' to install opencv")
  212.                 return 1
  213.             if output_para.v4l2Fmt != m.v4l2GetFmtByName("BGR24"):
  214.                 print("Output image format is not 'BGR24', Use the '-b BGR24' option to specify image format.")
  215.                 return 1
  216.             cv_display = Cv2Display("Cv2Display", None, sync, args.cvdisplay)
  217.             cv_display.module = last_module.addExternalConsumer("Cv2Display", cv_display, cv2_extcall_back)

  218.     if args.encodetype != -1:
  219.         enc = m.ModuleMppEnc(m.EncodeType(args.encodetype))
  220.         enc.setProductor(last_module)
  221.         enc.setBufferCount(8)
  222.         enc.setDuration(0) #Use the input source timestamp
  223.         ret = enc.init()
  224.         if ret < 0:
  225.             print("ModuleMppEnc init failed")
  226.             return 1
  227.         last_module = enc

  228.         if args.port != 0:
  229.             push_s = None
  230.             if args.push_type == 0:
  231.                 push_s = m.ModuleRtspServer("/live/0", args.port)
  232.             else:
  233.                 push_s = m.ModuleRtmpServer("/live/0", args.port)
  234.             push_s.setProductor(last_module)
  235.             push_s.setBufferCount(0)
  236.             if args.sync != -1:
  237.                 push_s.setSynchronize(m.Synchronize(m.SynchronizeType(args.sync)))

  238.             ret = push_s.init()
  239.             if ret < 0:
  240.                 print("push server init failed")
  241.                 return 1

  242.             if args.audio == True and args.push_type == 0:
  243.                 push_s_a = m.ModuleRtspServerExtend(push_s, "/live/0", args.port)
  244.                 if last_audio_module != None:
  245.                     push_s_a.setProductor(last_audio_module)
  246.                 else:
  247.                     push_s_a.setProductor(input_source)
  248.                 push_s_a.setAudioParameter(m.MEDIA_CODEC_AUDIO_AAC);
  249.                 ret = push_s_a.init()
  250.                 if ret < 0:
  251.                     print("Failed to init audio push server")
  252.                     return 1

  253.         if args.rtmp_url is not None:
  254.             push_c = m.ModuleRtmpClient(args.rtmp_url, m.ImagePara(), 0)
  255.             push_c.setProductor(last_module)
  256.             if args.sync != -1:
  257.                 push_c.setSynchronize(m.Synchronize(m.SynchronizeType(args.sync)))
  258.             ret = push_c.init()
  259.             if ret < 0:
  260.                 print("Fail to init rtmp client push")
  261.                 return 1

  262.         if args.gb28181_user_id is not None:
  263.             gb28181_c = m.ModuleGB28181Client(args.gb28181_user_id, "ffmedia")
  264.             gb28181_c.setProductor(last_module)
  265.             if args.sync != -1:
  266.                 gb28181_c.setSynchronize(m.Synchronize(m.SynchronizeType(args.sync)))

  267.             gb28181_c.setServerConfig(args.gb28181_server_id, args.gb28181_server_ip, \
  268.                                       args.gb28181_server_ip, args.gb28181_server_port, 3600)
  269.             ret = gb28181_c.init()
  270.             if ret < 0:
  271.                 print("Failed to init gb28181 client")
  272.                 return 1

  273.     if args.enmux is not None:
  274.         enm = m.ModuleFileWriter(args.enmux)
  275.         enm.setProductor(last_module)
  276.         ret = enm.init()
  277.         if ret < 0:
  278.             print("ModuleFileWriter init failed")
  279.             return 1

  280.         if args.audio:
  281.             enm_audio = m.ModuleFileWriterExtend(enm, args.enmux)
  282.             if last_audio_module != None:
  283.                 enm_audio.setProductor(last_audio_module)
  284.             else:
  285.                 enm_audio.setProductor(input_source)
  286.             enm_audio.setAudioParameter(0, 0, 0, m.MEDIA_CODEC_AUDIO_AAC);
  287.             ret = enm_audio.init()
  288.             if ret < 0:
  289.                 print("Failed to init audio writer")
  290.                 return 1

  291.     if args.save_file is not None:
  292.         file = open(args.save_file, "wb")
  293.         input_source.setOutputDataCallback(file, call_back)


  294.     input_source.start()
  295.     input_source.dumpPipe()
  296.     if input_audio_source != None:
  297.         input_audio_source.start()
  298.         input_audio_source.dumpPipe()
  299.     text = input("wait...")
  300.     if input_audio_source != None:
  301.         input_audio_source.dumpPipeSummary()
  302.         input_audio_source.stop()
  303.     input_source.dumpPipeSummary()
  304.     input_source.stop()

  305.     if args.save_file is not None:
  306.         file.close()


  307. if __name__ == "__main__":
  308.     main()
复制代码

程序启动命令是:

sudo /home/firefly/miniconda3/envs/pyev/bin/python3 ./czj_new_v5.py  -i rtmp://127.0.0.1:1935/live/stream_key -o 1920x1080 -d 0


然后回调函数里call_back1,无法正常解析出图像。
下面是打印日志。




可以请大佬帮忙看看怎么正常解析rtmp里的图像,处理后再发送走吗?





作者: dengkx    时间: 2024-9-13 17:18
解码模块解出来的是nv12格式数据,不是BGR24格式的,你可以添加个RGA模块将nv12格式转成BGR24,然后设置回调在RGA模块上处理数据。和demo.py 的-b BGR24操作一样
作者: chenwusong    时间: 2024-9-14 09:32
dengkx 发表于 2024-9-13 17:18
解码模块解出来的是nv12格式数据,不是BGR24格式的,你可以添加个RGA模块将nv12格式转成BGR24,然后设置回 ...

成功了成功了,大佬真厉害,加了这个转换后的数据果然可以正常解析了,多谢大佬指点。
多问一下,现在可以直接从/dev/video0,读取nv24的数据吗? 就是改成   python demo.py -i  /dev/video0 -d 0 这样运行的,之前也问过,那会说还没兼容从/dev/video0读取nv24的输入,请问现在有什么办法解决吗?
作者: dengkx    时间: 2024-9-14 11:39
chenwusong 发表于 2024-9-14 09:32
成功了成功了,大佬真厉害,加了这个转换后的数据果然可以正常解析了,多谢大佬指点。
多问一下,现在可 ...

读取应该没有问题,只是硬件不支持操作NV24格式的数据,所以他转不了BGR24给你使用




欢迎光临 Firefly开源社区 (https://dev.t-firefly.com/) Powered by Discuz! X3.1