h264.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package fmtp
  4. import (
  5. "encoding/hex"
  6. )
  7. func profileLevelIDMatches(a, b string) bool {
  8. aa, err := hex.DecodeString(a)
  9. if err != nil || len(aa) < 2 {
  10. return false
  11. }
  12. bb, err := hex.DecodeString(b)
  13. if err != nil || len(bb) < 2 {
  14. return false
  15. }
  16. return aa[0] == bb[0] && aa[1] == bb[1]
  17. }
  18. type h264FMTP struct {
  19. parameters map[string]string
  20. }
  21. func (h *h264FMTP) MimeType() string {
  22. return "video/h264"
  23. }
  24. // Match returns true if h and b are compatible fmtp descriptions
  25. // Based on RFC6184 Section 8.2.2:
  26. //
  27. // The parameters identifying a media format configuration for H.264
  28. // are profile-level-id and packetization-mode. These media format
  29. // configuration parameters (except for the level part of profile-
  30. // level-id) MUST be used symmetrically; that is, the answerer MUST
  31. // either maintain all configuration parameters or remove the media
  32. // format (payload type) completely if one or more of the parameter
  33. // values are not supported.
  34. // Informative note: The requirement for symmetric use does not
  35. // apply for the level part of profile-level-id and does not apply
  36. // for the other stream properties and capability parameters.
  37. func (h *h264FMTP) Match(b FMTP) bool {
  38. c, ok := b.(*h264FMTP)
  39. if !ok {
  40. return false
  41. }
  42. // test packetization-mode
  43. hpmode, hok := h.parameters["packetization-mode"]
  44. if !hok {
  45. return false
  46. }
  47. cpmode, cok := c.parameters["packetization-mode"]
  48. if !cok {
  49. return false
  50. }
  51. if hpmode != cpmode {
  52. return false
  53. }
  54. // test profile-level-id
  55. hplid, hok := h.parameters["profile-level-id"]
  56. if !hok {
  57. return false
  58. }
  59. cplid, cok := c.parameters["profile-level-id"]
  60. if !cok {
  61. return false
  62. }
  63. if !profileLevelIDMatches(hplid, cplid) {
  64. return false
  65. }
  66. return true
  67. }
  68. func (h *h264FMTP) Parameter(key string) (string, bool) {
  69. v, ok := h.parameters[key]
  70. return v, ok
  71. }