{"id":216,"date":"2026-11-02T02:09:18","date_gmt":"2026-11-01T23:09:18","guid":{"rendered":"https:\/\/offlabelhardware.com\/?p=216"},"modified":"2026-11-02T02:36:50","modified_gmt":"2026-11-01T23:36:50","slug":"4k-h-265-%e2%86%92-h-264-video-server-2","status":"publish","type":"post","link":"https:\/\/offlabelhardware.com\/?p=216","title":{"rendered":"4K H.265 \u2192 H.264 Video Server"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Part 2 \u2014 Reconstructing 4K Video on a Radeon HD 6570 and Athlon 64 X2<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><em>A continuation of <a href=\"https:\/\/offlabelhardware.com\/?p=163\">Part 1 \u2014 Making 4K Video More Compatible<\/a>.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/offlabelhardware.com\/?p=163\">Part 1<\/a>, I described the idea of a dedicated video server: take modern 4K H.265 video, convert it to H.264, and make it usable by older devices. The point was not to improve the original video. It was to bridge generations of hardware without having to replace every player and computer along the way.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That leaves another problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>H.264 is compatible with older hardware, but 4K H.264 is not necessarily easy for that hardware to play.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A graphics card may have an H.264 decoder and still be limited by the picture sizes, profiles, throughput or memory arrangements its video engine was designed to handle. In other words, changing the codec does not automatically remove the resolution problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So I decided to investigate a particularly old combination: an <strong>AMD Radeon HD 6570<\/strong> and an <strong>Athlon 64 X2 4200+<\/strong>, a dual-core processor running at 2.2 GHz. The computer ran Ubuntu Server without a desktop environment. Its display was connected through VGA at 1024 \u00d7 768.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The question was no longer simply whether the server could convert H.265 to H.264. It was:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Could the client reconstruct a complete 3840 \u00d7 2160 picture by dividing the work between hardware and software decoders?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The source material was a 3840 \u00d7 2160 HEVC Main10 video, converted upstream into H.264 test streams. The older client was not asked to decode H.265 or encode H.264 itself. The final reconstruction trials used a <strong>45-second excerpt (06:45\u201307:30) at 23.976 fps<\/strong>, containing <strong>1,079 frames<\/strong>. Although the graphics pipeline worked with a complete 4K picture internally, it scaled that image to <strong>1024 \u00d7 576 within the 1024 \u00d7 768 VGA output<\/strong>. That distinction matters: we investigated <strong>full-resolution reconstruction and real-time presentation<\/strong>, not native 4K display output.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Measuring capability rather than reading a specification sheet<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We ran three fundamentally different kinds of experiment. <strong>Isolated decoding<\/strong> measured how quickly a single H.264 stream could be decoded when no attempt was made to display it. <strong>Concurrent decoding<\/strong> ran multiple streams together and reported the rate of <strong>each stream<\/strong>, not their combined FPS. Finally, <strong>reconstruction tests<\/strong> decoded tiles, matched their presentation timestamps, assembled the image and, later, displayed it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Those numbers cannot be substituted for one another. A 60 fps decode-to-null test does not guarantee a 60 fps compositor. Similarly, a video that averages 24 fps over 45 seconds may still have individual frames that arrive late. Keeping these distinctions visible became as important as optimizing the code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Characterizing the Radeon HD 6570<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before attempting 4K reconstruction, I wanted to understand what the HD 6570 could actually decode. The card uses AMD&#8217;s Turks GPU and UVD video engine. Under Ubuntu Server, FFmpeg accessed it through the <code>r600<\/code> VA-API driver. The tests ran without a desktop environment so that we could measure decoding without confusing it with display performance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An H.264 hardware decoder has several different limits. It may accept one picture size but reject another. It may decode a single stream rapidly, yet become too slow when several streams compete for the same video engine. And an easy H.264 sequence may be decoded much faster than a demanding one at the same resolution. We investigated those questions separately.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The first multi-stream question: how many 1080p videos?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We began the concurrent-decoding experiments with familiar <strong>1920 \u00d7 1080 H.264 video<\/strong>, using <strong>30 fps per stream<\/strong> as the performance target. One stream was easy. Two still worked. At three, the card continued to decode every stream, but its throughput dropped below the target.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Simultaneous 1920 \u00d7 1080 streams<\/th><th>Decoding speed, per stream<\/th><th>Meets 30 fps?<\/th><\/tr><\/thead><tbody><tr><td>1<\/td><td><strong>65 fps<\/strong><\/td><td>Yes<\/td><\/tr><tr><td>2<\/td><td><strong>36\u201337 fps<\/strong><\/td><td>Yes<\/td><\/tr><tr><td>3<\/td><td><strong>24 fps<\/strong><\/td><td>No<\/td><\/tr><tr><td>4<\/td><td><strong>18\u201319 fps<\/strong><\/td><td>No<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These first trials used 150 frames per stream. <strong>\u201cThree streams failed\u201d did not mean a decoder error:<\/strong> three streams completed successfully, but they were no longer fast enough to sustain the chosen 30 fps target. Multiplying the per-stream numbers by the stream count gives an aggregate of roughly <strong>65\u201375 decoded 1080p frames per second<\/strong> across these trials. This suggested that the streams were competing for a relatively fixed decoding capacity, rather than receiving independent full-speed video engines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is a subtle point about the word <em>failed<\/em>. We deliberately chose <strong>30 fps<\/strong> as the pass criterion in this concurrency exploration, even though our later movie excerpt was <strong>23.976 fps<\/strong>. Three 1080p streams at approximately 24 fps were not a robust 30 fps solution, and they left essentially no margin for the 23.976 fps source. That is why the next experiment was not to add another decoder, but to <strong>reduce the amount of work per stream<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That immediately led to another question: <strong>if we made each stream smaller, could the HD 6570 handle three or even four simultaneously at 30 fps?<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Smaller pictures, more simultaneous streams<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We repeated the concurrent-decoding tests at three smaller resolutions, running 600 frames per stream. The results were revealing:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Resolution of each stream<\/th><th>1 stream<\/th><th>2 streams<\/th><th>3 streams<\/th><th>4 streams<\/th><\/tr><\/thead><tbody><tr><td><strong>1920 \u00d7 1080<\/strong><\/td><td>65<\/td><td>36\u201337<\/td><td>24<\/td><td>18\u201319<\/td><\/tr><tr><td><strong>1280 \u00d7 1152<\/strong><\/td><td>102<\/td><td>53<\/td><td><strong>35<\/strong><\/td><td>26<\/td><\/tr><tr><td><strong>1280 \u00d7 1024<\/strong><\/td><td>113<\/td><td>59<\/td><td><strong>39<\/strong><\/td><td><strong>30\u201331<\/strong><\/td><\/tr><tr><td><strong>1280 \u00d7 720<\/strong><\/td><td>156<\/td><td>82<\/td><td><strong>55<\/strong><\/td><td><strong>41<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>All values are measured frames per second <strong>per stream<\/strong>, not the sum across streams. The 1080p row comes from the earlier 150-frame tests; the smaller-resolution rows are 600-frame tests, so the figures describe distinct experiments.<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"605\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams-1024x605.png\" alt=\"\" class=\"wp-image-232\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams-1024x605.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams-300x177.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams-768x453.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams-1536x907.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/08_hd6570_concurrent_streams.png 1890w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The Radeon HD 6570 could decode two 1080p H.264 streams above 30 fps, but reducing the resolution allowed three or even four simultaneous streams to reach that target.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The contrast with the initial 1080p result is significant. <strong>Three 1280 \u00d7 1152 streams ran at 35 fps each<\/strong>, while <strong>four 1280 \u00d7 1024 streams just reached 30\u201331 fps each<\/strong>. With four 1280 \u00d7 720 streams, each stream reached 41 fps. We did not test more than four streams in this particular set, so that is a demonstrated result, not a claim about the absolute maximum number of simultaneous streams.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"474\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity-1024x474.png\" alt=\"\" class=\"wp-image-224\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity-1024x474.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity-300x139.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity-768x356.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity-1536x711.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/11_hd6570_concurrency_capacity.png 1836w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The number of simultaneous H.264 streams meeting the 30 fps requirement depended strongly on their individual resolutions<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These numbers changed the direction of the investigation. Instead of treating 1080p as an indivisible unit, we could select tile dimensions that gave the GPU enough throughput for several simultaneous streams. <strong>A 1280 \u00d7 720 stream contains fewer than half as many pixels as 1920 \u00d7 1080<\/strong>; the difference was large enough that four 720p streams each exceeded 30 fps.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At the same time, the test showed why a blanket statement such as \u201cthe HD 6570 can decode four videos\u201d would be misleading. <strong>How many streams?<\/strong> depended on <strong>how large and demanding each stream was<\/strong>. The next step was to find dimensions that suited the decoder, then decide how those pieces could be arranged into a larger picture.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exploring unusual dimensions and single-stream boundaries<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We also characterized single-stream speed at a wider set of resolutions. The measurements below come from a separate resolution sweep; differences between its values and the concurrency tests reflect different test runs and workloads.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>H.264 stream resolution<\/th><th>Measured throughput<\/th><\/tr><\/thead><tbody><tr><td>1280 \u00d7 720<\/td><td><strong>132 fps<\/strong><\/td><\/tr><tr><td>1280 \u00d7 800<\/td><td>121 fps<\/td><\/tr><tr><td>1280 \u00d7 900<\/td><td>109 fps<\/td><\/tr><tr><td>1280 \u00d7 960<\/td><td>104 fps<\/td><\/tr><tr><td>1280 \u00d7 1024<\/td><td>99 fps<\/td><\/tr><tr><td>1280 \u00d7 1080<\/td><td>93 fps<\/td><\/tr><tr><td>1440 \u00d7 900<\/td><td>98 fps<\/td><\/tr><tr><td>1440 \u00d7 1080<\/td><td>84 fps<\/td><\/tr><tr><td>1600 \u00d7 900<\/td><td>89 fps<\/td><\/tr><tr><td>1600 \u00d7 1000<\/td><td>82 fps<\/td><\/tr><tr><td>1600 \u00d7 1080<\/td><td>77 fps<\/td><\/tr><tr><td>1920 \u00d7 1080<\/td><td>66 fps<\/td><\/tr><tr><td>2048 \u00d7 1080<\/td><td>68 fps<\/td><\/tr><tr><td>2048 \u00d7 1152<\/td><td>59 fps<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"633\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep-1024x633.png\" alt=\"\" class=\"wp-image-230\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep-1024x633.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep-300x185.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep-768x475.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep-1536x950.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/06_hd6570_full_resolution_sweep.png 1980w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Testing different image dimensions revealed how the HD 6570&#8217;s decoding throughput changed with resolution, including unusual frame sizes.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Within this particular sweep, <strong>1280 \u00d7 720 reached 132 fps<\/strong>, while even 2048 \u00d7 1152 maintained 59 fps. The <strong>highest single-stream figure across the separately recorded tests was 156 fps at 1280 \u00d7 720<\/strong> in the concurrency batch. The two 720p results are not a contradiction: the test content and procedures were different, so the correct interpretation is that they are measurements from separate runs, not a universal maximum.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A separate FFmpeg\/null-output run at 2048 \u00d7 1152 completed <strong>1,079 frames in 19.98 seconds<\/strong>, or about <strong>54 fps<\/strong>. We also tested unconventional portrait-oriented dimensions, including <strong>1080 \u00d7 1920 and 720 \u00d7 1280<\/strong>, which this VA-API decoding path rejected. That does not, on its own, prove every imaginable hardware limit, but it demonstrates that <strong>pixel count, accepted dimensions, and decoding throughput are three distinct questions<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bitrate changed the result as well<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">So far, the experiments established that lower resolution increased the number of simultaneous streams. But could we predict decoding performance from pixel count alone? To answer that, we compared different H.264 encodings of the <strong>same real-world 1920 \u00d7 1080, 23.976 fps video<\/strong> (<code>video_decode_test2.mp4<\/code>). Each version contained approximately 3,207 frames. We tested an approximately 1.76 Mbps original and re-encodes at approximately 19.94 and 29.01 Mbps. The latter was the actual bitrate reached by encodes targeting higher rates; it was not a 40 or 60 Mbps result.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Actual bitrate<\/th><th>HD 6570, GPU decoding<\/th><th>Athlon 64 X2, CPU decoding<\/th><\/tr><\/thead><tbody><tr><td><strong>1.76 Mbps<\/strong><\/td><td><strong>73 fps<\/strong><\/td><td><strong>93 fps<\/strong><\/td><\/tr><tr><td><strong>19.94 Mbps<\/strong><\/td><td><strong>60 fps<\/strong><\/td><td><strong>47 fps<\/strong><\/td><\/tr><tr><td><strong>29.01 Mbps<\/strong><\/td><td><strong>53 fps<\/strong><\/td><td><strong>39 fps<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These were unrestricted <strong>single-stream FFmpeg decode-to-null<\/strong> measurements. They are not display FPS, and the original and re-encoded files were not necessarily equally demanding H.264 bitstreams apart from bitrate. The encoder&#8217;s motion prediction, reference-frame decisions and other coding choices also matter. Nevertheless, for these actual files, the Radeon fell from <strong>73 to 53 fps<\/strong>, while the Athlon fell from <strong>93 to 39 fps<\/strong>. At the lowest rate, the CPU was faster in this particular test; at the highest rate, the GPU was faster. <strong>The Athlon was much more sensitive to the demanding encodes.<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu-1024x608.png\" alt=\"\" class=\"wp-image-222\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu-1024x608.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu-300x178.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu-768x456.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu-1536x912.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/09_h264_bitrate_cpu_gpu.png 1728w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Comparing hardware and software decoding at different H.264 bitrates helped establish the practical roles of the Radeon HD 6570 and Athlon 64 X2.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We also ran <strong>two GPU-decoded streams and two CPU-decoded streams concurrently<\/strong>. This was still a decode-capacity test, <strong>not yet a four-tile composited video<\/strong>. Each of the four decoders processed its own 1080p stream of the tested bitrate:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Bitrate per 1080p stream<\/th><th>Each GPU stream<\/th><th>Each CPU stream<\/th><th>23.976 fps source rate<\/th><\/tr><\/thead><tbody><tr><td>1.76 Mbps<\/td><td>~36 fps<\/td><td>43\u201344 fps<\/td><td>All four above target<\/td><\/tr><tr><td>19.94 Mbps<\/td><td>~30 fps<\/td><td>~24 fps<\/td><td>Borderline on CPU<\/td><\/tr><tr><td>29.01 Mbps<\/td><td>~27 fps<\/td><td>~19 fps<\/td><td>CPU streams below target<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These mixed trials were important for the next stage. They showed that the old Athlon was not incapable of participating in a multi-stream reconstruction; it could perform useful decoding work, provided we controlled the <strong>number of pixels assigned to it and the difficulty of the H.264 stream<\/strong>. They also warned us not to rely on a low-bitrate success as proof that every 1080p file would behave the same way.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit-1024x608.png\" alt=\"\" class=\"wp-image-223\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit-1024x608.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit-300x178.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit-768x456.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit-1536x912.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/10_four_stream_bitrate_limit.png 1728w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Combined hardware and software decoding experiments revealed the effect of increasing bitrate on multi-stream throughput.<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Proving that two GPU streams could become one picture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Decoding several streams was only the first half of the idea. To use those streams as tiles of a larger image, we had to combine them without wasting time copying complete frames between the GPU and system memory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We split a <strong>2048 \u00d7 1152<\/strong> picture into two <strong>2048 \u00d7 576<\/strong> H.264 streams, each approximately <strong>10 Mbps<\/strong>. The Radeon decoded both at around <strong>57 fps per stream<\/strong>. The new GPU compositor then reconstructed the image using textures and a shader. It processed <strong>1,079 synchronized frame pairs in 21.663 seconds \u2014 49.81 reconstructed frames per second<\/strong> \u2014 with zero timestamp mismatches and no full-frame CPU readback.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"410\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles-1024x410.png\" alt=\"\" class=\"wp-image-231\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles-1024x410.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles-300x120.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles-768x307.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles-1536x614.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/07_dual_gpu_tiles.png 1800w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Two independently decoded H.264 streams were reconstructed into a single 2048 \u00d7 1152 image using GPU composition.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A separate earlier FFmpeg test also completed a <strong>2048 \u00d7 1152 GPU-only decode\/reconstruction workload at about 54 fps<\/strong>, but the <strong>49.81 fps<\/strong> figure above is the more informative result for the dedicated two-tile GPU compositor: it includes synchronized tile handling and composition, not just unrestricted decoder output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This was the proof of concept that connected the earlier benchmarks to the larger project. <strong>The HD 6570 did not need to decode one oversized frame. It could decode supported pieces and let a shader reconstruct the picture.<\/strong> We were now ready to go beyond GPU-only stitching and ask how much of the remaining image area the Athlon could handle in software.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Then, test what the Athlon could contribute<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Having measured the Athlon&#8217;s software decoder as well as the Radeon, we could make a more sensible division of the image. The Athlon 64 X2 4200+ is a dual-core, 2.2 GHz processor from an era long before software 4K H.264 playback was a reasonable expectation. We were not going to give it the entire 4K picture. Instead, the GPU would decode two upper tiles while the CPU decoded a carefully sized lower region. The bitrate experiments had already shown why the CPU&#8217;s assigned workload had to remain manageable. What mattered now was whether all three tiles could arrive in time to reconstruct each source frame.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We first worked at <strong>2880 \u00d7 1620<\/strong>, a step beyond conventional full HD but not yet the full 4K workload. An early FFmpeg-based hybrid reconstruction finished <strong>1,079 frames in approximately 41.67 seconds (about 25.9 fps)<\/strong>. That was just above the 23.976 fps movie rate, but offered little room for the other work a real player must perform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After moving the tile composition into a dedicated OpenGL ES pipeline and reducing unnecessary transfers, the <strong>2880 \u00d7 1620 offscreen compositor reached 40.04 fps<\/strong>. These are results from different implementations, so the comparison is about the development progression rather than an isolated single-variable speedup. Nevertheless, it demonstrated that <strong>where we stitched the tiles<\/strong> could matter almost as much as <strong>where we decoded them<\/strong>. That gave us confidence to attempt 3840 \u00d7 2160.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Finding a practical stitching strategy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next question was where the decoded pieces should meet. We explored the following approaches in order of increasing specialization:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Approach<\/th><th>What it does<\/th><th>Why it mattered<\/th><\/tr><\/thead><tbody><tr><td><strong>FFmpeg-side reconstruction<\/strong><\/td><td>Decode and combine the picture using a general-purpose processing pipeline<\/td><td>A useful first proof of concept, but extra frame movement and processing limited the available margin<\/td><\/tr><tr><td><strong>CPU-side assembly<\/strong><\/td><td>Copy decoded tiles into a complete frame in system memory before handing it to the graphics card<\/td><td>Straightforward, but potentially expensive at millions of pixels per frame on an Athlon X2<\/td><\/tr><tr><td><strong>GPU shader stitching<\/strong><\/td><td>Leave GPU-decoded images in GPU-accessible surfaces, upload only the software-decoded tile and compose the image in a shader<\/td><td>Avoided full-4K CPU copies and let the GPU do scaling and assembly<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We ultimately concentrated on the third strategy. The hardware-decoded top tiles remained on the Radeon; the Athlon decoded the bottom tile into system memory; OpenGL ES sampled the three tile textures, selected the appropriate region for each final pixel, and scaled the assembled image for display. The program did not need to materialize a full 3840 \u00d7 2160 picture in system RAM.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"415\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-1024x415.png\" alt=\"\" class=\"wp-image-225\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-1024x415.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-300x122.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-768x311.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-1536x623.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/12_composition_evolution-2048x830.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The reconstruction pipeline evolved through several stitching strategies to reduce CPU processing and unnecessary memory transfers.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This distinction explains a result that would otherwise seem surprising. <strong>We were not asking the Athlon to decode, stitch and resize the entire 4K image.<\/strong> It only decoded the part assigned to it. The GPU remained responsible for decoding the other tiles, assembling the image and presenting it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What we optimized<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We iterated through several implementation details:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>GPU surface reuse:<\/strong> VA-API hardware decode surfaces were imported into EGL\/OpenGL ES textures using DRM PRIME2\/DMA-BUF rather than copied back to system RAM. A small cache avoided repeated surface import for recurring VA surfaces; in one 1,079-frame run, the top paths recorded 1,074 cache hits and five misses each.<\/li>\n\n\n\n<li><strong>Direct planar upload:<\/strong> the software-decoded bottom image used three <code>GL_R8<\/code> planes for Y, U and V. <code>GL_UNPACK_ROW_LENGTH<\/code> allowed us to respect FFmpeg line strides without repacking every frame into an intermediate buffer.<\/li>\n\n\n\n<li><strong>Shader composition:<\/strong> OpenGL ES reconstructed the 3840 \u00d7 2160 image logically from three tile textures and performed the display downscale on the GPU, with no full-4K CPU readback.<\/li>\n\n\n\n<li><strong>Direct display:<\/strong> the headless server used GBM\/EGL and DRM\/KMS to present to VGA, bypassing a desktop compositor.<\/li>\n\n\n\n<li><strong>Display\/compute overlap:<\/strong> rather than blocking immediately for each DRM page flip, we deferred the wait while preparing the next frame. This recovered useful throughput and reduced idle time.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"465\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture-1024x465.png\" alt=\"\" class=\"wp-image-229\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture-1024x465.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture-300x136.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture-768x349.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture-1536x698.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/04_tile_architecture.png 1650w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The hybrid pipeline combined two hardware-decoded upper tiles with one software-decoded lower tile to reconstruct a complete 4K frame.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">The 4K tile arrangements<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We tried two closely related 4K partitions. The first used two <strong>1920 \u00d7 1080<\/strong> top tiles with a <strong>3840 \u00d7 1080<\/strong> bottom tile. That offscreen configuration reached <strong>25.69 fps<\/strong>, while its paced VGA version reached <strong>23.56 fps<\/strong>. We then shifted the boundary down: two <strong>1920 \u00d7 1152<\/strong> top tiles, with a shorter <strong>3840 \u00d7 1008<\/strong> bottom tile. This transferred more work to the Radeon and reduced the CPU&#8217;s assigned pixel count.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The boundary adjustment was small on screen but meaningful for this processor:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Contribution<\/th><th>1080-pixel top boundary<\/th><th>1152-pixel top boundary<\/th><\/tr><\/thead><tbody><tr><td>Each GPU tile<\/td><td>1920 \u00d7 1080<\/td><td>1920 \u00d7 1152<\/td><\/tr><tr><td>Software-decoded bottom tile<\/td><td>3840 \u00d7 1080<\/td><td>3840 \u00d7 1008<\/td><\/tr><tr><td>Pixels assigned to CPU per frame<\/td><td>4,147,200<\/td><td>3,870,720<\/td><\/tr><tr><td>Share of 4K pixels decoded by CPU<\/td><td>50.0%<\/td><td>46.7%<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In other words, increasing the height of each GPU tile by <strong>72 pixels<\/strong> removed <strong>276,480 pixels per frame<\/strong>, or <strong>6.7%<\/strong>, from the CPU tile. It did not remove that work from the pipeline; it reassigned it to the HD 6570.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"481\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison-1024x481.png\" alt=\"\" class=\"wp-image-226\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison-1024x481.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison-300x141.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison-768x361.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison-1536x721.png 1536w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/13_4k_tile_boundary_comparison.png 1955w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Moving the horizontal tile boundary from 1080 to 1152 pixels transferred additional decoding work from the Athlon to the Radeon.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The 1152-pixel split delivered <strong>26.81 fps offscreen<\/strong> in the initial full-4K test and about <strong>23.75 fps<\/strong> when paced to VGA. The more consequential change was not another split: it was overlapping the DRM page-flip wait with preparation of the next frame. In the 1152-pixel configuration, an unpaced overlapping KMS test reached <strong>28.22 fps<\/strong> over 1,079 frames (38.241 seconds). That is approximately <strong>17.7% more throughput<\/strong> than the 23.976 fps content rate. A paced overlap run measured <strong>23.99 fps<\/strong>, essentially the target average frame rate.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Selected measured results<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The record also includes the <strong>25.9 fps<\/strong> early 1620p FFmpeg prototype and <strong>49.81 fps<\/strong> two-tile GPU compositor discussed above; they are not repeated in the 4K table because they processed different frame sizes and included different stages of work.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"492\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/01_performance_progression-1024x492.png\" alt=\"\" class=\"wp-image-227\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/01_performance_progression-1024x492.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/01_performance_progression-300x144.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/01_performance_progression-768x369.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/01_performance_progression.png 1500w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Successive optimizations improved reconstruction throughput until full-4K processing exceeded the original video&#8217;s 23.976 fps frame rate.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Experiment<\/th><th>Offscreen \/ output<\/th><th>Measured throughput<\/th><\/tr><\/thead><tbody><tr><td>Hybrid 2880 \u00d7 1620<\/td><td>Offscreen<\/td><td>40.04 fps<\/td><\/tr><tr><td>4K, 1080-pixel top tiles<\/td><td>Offscreen<\/td><td>25.69 fps<\/td><\/tr><tr><td>4K, 1080-pixel top tiles<\/td><td>Paced VGA<\/td><td>23.56 fps<\/td><\/tr><tr><td>4K, 1152-pixel top tiles<\/td><td>Offscreen<\/td><td>26.81 fps<\/td><\/tr><tr><td>4K, 1152-pixel top tiles<\/td><td>Paced VGA, initial<\/td><td>23.75 fps<\/td><\/tr><tr><td>4K, 1152-pixel top tiles<\/td><td>Sequential unpaced VGA<\/td><td>24.50 fps<\/td><\/tr><tr><td>4K, 1152-pixel top tiles<\/td><td>Overlapping unpaced VGA<\/td><td><strong>28.22 fps<\/strong><\/td><\/tr><tr><td>4K, 1152-pixel top tiles<\/td><td>Overlapping paced VGA<\/td><td><strong>23.99 fps<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The measurements above were collected during different iterations and should not be read as a perfectly controlled apples-to-apples codec benchmark. <strong>Offscreen<\/strong> means frames were reconstructed without waiting for a physical screen; <strong>unpaced VGA<\/strong> means the display path was active but the program was not constrained to movie timing; <strong>paced VGA<\/strong> means playback was scheduled to the 23.976 fps presentation clock. They do, however, show the progression from a workable concept to full-frame reconstruction with practical 24 fps <strong>average<\/strong> throughput.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why the last optimizations mattered<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the 28.22 fps unpaced overlap run, the accumulated stage timings were approximately <strong>25.13 seconds decoding<\/strong>, <strong>1.80 seconds VA synchronization\/import<\/strong>, <strong>5.06 seconds CPU texture upload<\/strong>, and <strong>5.42 seconds GL draw\/finish<\/strong>. These are per-stage totals and should not be summed as if they were a single critical path in a fully overlapping system.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/02_stage_timings-1024x512.png\" alt=\"\" class=\"wp-image-228\" srcset=\"https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/02_stage_timings-1024x512.png 1024w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/02_stage_timings-300x150.png 300w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/02_stage_timings-768x384.png 768w, https:\/\/offlabelhardware.com\/wp-content\/uploads\/2026\/11\/02_stage_timings.png 1350w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Profiling the optimized pipeline illustrates the relative costs of video decoding, synchronization, texture uploads and GPU composition.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The CPU tile remained the expensive part, but the optimization work mattered. Caching VA surfaces avoided unnecessary re-imports. Direct planar texture uploads eliminated row repacking. GPU-side reconstruction avoided a potentially large full-frame system-memory copying path. Finally, deferring the DRM flip wait meant the main loop could use time that had previously been spent waiting for the display.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For scale, a complete 3840 \u00d7 2160 image in three-plane 8-bit 4:2:0 format contains approximately <strong>12.4 MB of active pixel samples per frame<\/strong> (before stride or surface overhead). At 24 fps, repeatedly moving even one whole frame through system memory would involve roughly <strong>299 MB\/s of pixel data<\/strong> per copy. It is not that the graphics card could never move that much data; it is that avoiding needless transfers is valuable when the rest of the system is already running near its limit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What we demonstrated \u2014 and what we did not<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The HD 6570 and Athlon 64 X2 4200+ reconstructed <strong>all 3840 \u00d7 2160 pixels<\/strong> of the test video inside an OpenGL ES pipeline. On our 1024 \u00d7 768 VGA display, the result was downscaled to a letterboxed image. We also achieved average throughput above the 23.976 fps source rate and measured paced presentation close to 24 fps. The earlier stream-capacity and bitrate benchmarks explain why distributing the pixels across the Radeon and Athlon was necessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These results do <strong>not<\/strong> establish glitch-free playback of every frame. Some displayed intervals were longer than the nominal 41.7 ms movie frame period. Nor do they establish native 4K HDMI output, a general bitrate ceiling, or universal compatibility with arbitrary H.264 files. In one upstream conversion variant we also observed a colour cast; we therefore have not treated end-to-end colour accuracy as validated. The full-4K reconstruction trial used a <strong>specific 45-second, 1,079-frame excerpt<\/strong>, so other scenes and encodings may stress the hardware differently. Detailed diagnosis of occasional late frames is outside the scope of this installment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The useful conclusion is architectural: a graphics card that cannot handle a particular video as one stream may still contribute substantially to its reconstruction when decoding, memory transfer, composition and presentation are treated as separate engineering problems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where Part 2 ends<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our final trial for this article was the <strong>1920 \u00d7 1152 + 1920 \u00d7 1152 + 3840 \u00d7 1008<\/strong> arrangement. The measured result was enough to demonstrate full-resolution internal reconstruction and approximately real-time display on remarkably old hardware. There were still occasional longer display intervals, so this is not a claim of perfectly smooth playback under every condition. The detailed investigation of those intervals belongs to a later stage of the project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The broader Off-Label Hardware lesson is that a nominal codec or resolution limit is not always the end of the story. Sometimes the more interesting question is <strong>which parts of the job the hardware can still do well \u2014 and how to arrange the rest around it.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/offlabelhardware.com\/?p=169\">\u2190<\/a><a href=\"https:\/\/offlabelhardware.com\/?p=163\" data-type=\"link\" data-id=\"https:\/\/offlabelhardware.com\/?p=163\">Part 1 \u2014 Making 4K Video More Compatible<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Can a 20-year-old Athlon 64 X2 and Radeon HD 6570 handle 4K video? In Part 2, we explore the limits of H.264 hardware decoding through resolution, bitrate and multi-stream tests, then combine GPU and CPU decoding with optimized tile stitching to reconstruct full 4K video at real-time frame rates.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"project","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-216","post","type-post","status-publish","format-standard","hentry","category-projects"],"_links":{"self":[{"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/posts\/216","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=216"}],"version-history":[{"count":5,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/posts\/216\/revisions"}],"predecessor-version":[{"id":240,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=\/wp\/v2\/posts\/216\/revisions\/240"}],"wp:attachment":[{"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=216"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=216"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/offlabelhardware.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=216"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}